mirror of
https://github.com/corda/corda.git
synced 2025-03-15 08:41:04 +00:00
implement jar and file URL stream handlers
This commit is contained in:
parent
31eb047391
commit
3dd091c67a
@ -34,12 +34,13 @@ public class SystemClassLoader extends ClassLoader {
|
||||
return c == null ? null : getClass(c);
|
||||
}
|
||||
|
||||
private native boolean resourceExists(String name);
|
||||
private native String resourceURLPrefix(String name);
|
||||
|
||||
protected URL findResource(String name) {
|
||||
if (resourceExists(name)) {
|
||||
String prefix = resourceURLPrefix(name);
|
||||
if (prefix != null) {
|
||||
try {
|
||||
return new URL("resource:" + name);
|
||||
return new URL(prefix + name);
|
||||
} catch (MalformedURLException ignored) { }
|
||||
}
|
||||
return null;
|
||||
|
44
classpath/avian/file/Handler.java
Normal file
44
classpath/avian/file/Handler.java
Normal file
@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian.file;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Handler extends URLStreamHandler {
|
||||
protected URLConnection openConnection(URL url) {
|
||||
return new FileURLConnection(url);
|
||||
}
|
||||
|
||||
private static class FileURLConnection extends URLConnection {
|
||||
public FileURLConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return (int) new File(url.getFile()).length();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new FileInputStream(url.getFile());
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
84
classpath/avian/jar/Handler.java
Normal file
84
classpath/avian/jar/Handler.java
Normal file
@ -0,0 +1,84 @@
|
||||
/* Copyright (c) 2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian.jar;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
public class Handler extends URLStreamHandler {
|
||||
protected URLConnection openConnection(URL url) {
|
||||
return new MyJarURLConnection(url);
|
||||
}
|
||||
|
||||
protected void parseURL(URL url, String s, int start, int end)
|
||||
throws MalformedURLException
|
||||
{
|
||||
// skip "jar:"
|
||||
s = s.toString().substring(4);
|
||||
int index = s.indexOf("!/");
|
||||
if (index < 0) {
|
||||
throw new MalformedURLException();
|
||||
}
|
||||
|
||||
URL file = new URL(s.substring(0, index));
|
||||
if (! "file".equals(file.getProtocol())) {
|
||||
throw new RuntimeException
|
||||
("protocol " + file.getProtocol() + " not yet supported");
|
||||
}
|
||||
|
||||
url.set("jar", "", -1, s, null);
|
||||
}
|
||||
|
||||
private static class MyJarURLConnection extends JarURLConnection {
|
||||
private final JarFile file;
|
||||
private final JarEntry entry;
|
||||
|
||||
public MyJarURLConnection(URL url) {
|
||||
super(url);
|
||||
|
||||
String s = url.getFile();
|
||||
int index = s.indexOf("!/");
|
||||
|
||||
try {
|
||||
this.file = new JarFile(new URL(s.substring(0, index)).getFile());
|
||||
this.entry = this.file.getJarEntry(s.substring(index + 2));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JarFile getJarFile() throws IOException {
|
||||
return file;
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return entry.getSize();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return file.getInputStream(entry);
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
22
classpath/java/net/JarURLConnection.java
Normal file
22
classpath/java/net/JarURLConnection.java
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright (c) 2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public abstract class JarURLConnection extends URLConnection {
|
||||
public JarURLConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
public abstract JarFile getJarFile() throws IOException;
|
||||
}
|
@ -73,13 +73,17 @@ public final class URL {
|
||||
{
|
||||
if ("resource".equals(protocol)) {
|
||||
return new avian.resource.Handler();
|
||||
} else if ("file".equals(protocol)) {
|
||||
return new avian.file.Handler();
|
||||
} else if ("jar".equals(protocol)) {
|
||||
return new avian.jar.Handler();
|
||||
} else {
|
||||
throw new MalformedURLException("unknown protocol: " + protocol);
|
||||
}
|
||||
}
|
||||
|
||||
protected void set(String protocol, String host, int port, String file,
|
||||
String ref)
|
||||
public void set(String protocol, String host, int port, String file,
|
||||
String ref)
|
||||
{
|
||||
this.protocol = protocol;
|
||||
this.host = host;
|
||||
|
@ -13,7 +13,9 @@ package java.net;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class URLStreamHandler {
|
||||
protected void parseURL(URL url, String s, int start, int end) {
|
||||
protected void parseURL(URL url, String s, int start, int end)
|
||||
throws MalformedURLException
|
||||
{
|
||||
String protocol = s.substring(0, start - 1);
|
||||
s = s.substring(start, end);
|
||||
|
||||
|
15
classpath/java/util/jar/JarEntry.java
Normal file
15
classpath/java/util/jar/JarEntry.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.jar;
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public abstract class JarEntry extends ZipEntry { }
|
77
classpath/java/util/jar/JarFile.java
Normal file
77
classpath/java/util/jar/JarFile.java
Normal file
@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public class JarFile extends ZipFile {
|
||||
public JarFile(String name) throws IOException {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public JarFile(File file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
public Enumeration<JarEntry> entries() {
|
||||
return (Enumeration<JarEntry>) makeEnumeration(JarEntryFactory.Instance);
|
||||
}
|
||||
|
||||
public JarEntry getJarEntry(String name) {
|
||||
return (JarEntry) getEntry(JarEntryFactory.Instance, name);
|
||||
}
|
||||
|
||||
private static class MyJarEntry extends JarEntry {
|
||||
public final Window window;
|
||||
public final int pointer;
|
||||
|
||||
public MyJarEntry(Window window, int pointer) {
|
||||
this.window = window;
|
||||
this.pointer = pointer;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
try {
|
||||
return entryName(window, pointer);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCompressedSize() {
|
||||
try {
|
||||
return compressedSize(window, pointer);
|
||||
} catch (IOException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
try {
|
||||
return uncompressedSize(window, pointer);
|
||||
} catch (IOException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class JarEntryFactory implements EntryFactory {
|
||||
public static final JarEntryFactory Instance = new JarEntryFactory();
|
||||
|
||||
public ZipEntry makeEntry(Window window, int pointer) {
|
||||
return new MyJarEntry(window, pointer);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,4 +13,5 @@ package java.util.zip;
|
||||
public abstract class ZipEntry {
|
||||
public abstract String getName();
|
||||
public abstract int getCompressedSize();
|
||||
public abstract int getSize();
|
||||
}
|
||||
|
@ -63,13 +63,23 @@ public class ZipFile {
|
||||
return index.size();
|
||||
}
|
||||
|
||||
protected Enumeration<? extends ZipEntry> makeEnumeration
|
||||
(EntryFactory factory)
|
||||
{
|
||||
return new MyEnumeration(factory, window, index.values().iterator());
|
||||
}
|
||||
|
||||
public Enumeration<? extends ZipEntry> entries() {
|
||||
return new MyEnumeration(window, index.values().iterator());
|
||||
return makeEnumeration(ZipEntryFactory.Instance);
|
||||
}
|
||||
|
||||
protected ZipEntry getEntry(EntryFactory factory, String name) {
|
||||
Integer pointer = index.get(name);
|
||||
return (pointer == null ? null : factory.makeEntry(window, pointer));
|
||||
}
|
||||
|
||||
public ZipEntry getEntry(String name) {
|
||||
Integer pointer = index.get(name);
|
||||
return (pointer == null ? null : new MyZipEntry(window, pointer));
|
||||
return getEntry(ZipEntryFactory.Instance, name);
|
||||
}
|
||||
|
||||
public InputStream getInputStream(ZipEntry entry) throws IOException {
|
||||
@ -126,7 +136,7 @@ public class ZipFile {
|
||||
return get2(w, p + 28);
|
||||
}
|
||||
|
||||
private static String entryName(Window w, int p) throws IOException {
|
||||
protected static String entryName(Window w, int p) throws IOException {
|
||||
int length = entryNameLength(w, p);
|
||||
return new String(w.data, w.seek(p + 46, length), length);
|
||||
}
|
||||
@ -135,10 +145,14 @@ public class ZipFile {
|
||||
return get2(w, p + 10);
|
||||
}
|
||||
|
||||
private static int compressedSize(Window w, int p) throws IOException {
|
||||
protected static int compressedSize(Window w, int p) throws IOException {
|
||||
return get4(w, p + 20);
|
||||
}
|
||||
|
||||
protected static int uncompressedSize(Window w, int p) throws IOException {
|
||||
return get4(w, p + 24);
|
||||
}
|
||||
|
||||
private static int fileNameLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 28);
|
||||
}
|
||||
@ -186,7 +200,7 @@ public class ZipFile {
|
||||
file.close();
|
||||
}
|
||||
|
||||
private static class Window {
|
||||
protected static class Window {
|
||||
private final RandomAccessFile file;
|
||||
public final byte[] data;
|
||||
public int start;
|
||||
@ -255,13 +269,37 @@ public class ZipFile {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
try {
|
||||
return uncompressedSize(window, pointer);
|
||||
} catch (IOException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected interface EntryFactory {
|
||||
public ZipEntry makeEntry(Window window, int pointer);
|
||||
}
|
||||
|
||||
private static class ZipEntryFactory implements EntryFactory {
|
||||
public static final ZipEntryFactory Instance = new ZipEntryFactory();
|
||||
|
||||
public ZipEntry makeEntry(Window window, int pointer) {
|
||||
return new MyZipEntry(window, pointer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyEnumeration implements Enumeration<ZipEntry> {
|
||||
private final EntryFactory factory;
|
||||
private final Window window;
|
||||
private final Iterator<Integer> iterator;
|
||||
|
||||
public MyEnumeration(Window window, Iterator<Integer> iterator) {
|
||||
public MyEnumeration(EntryFactory factory, Window window,
|
||||
Iterator<Integer> iterator)
|
||||
{
|
||||
this.factory = factory;
|
||||
this.window = window;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
@ -271,7 +309,7 @@ public class ZipFile {
|
||||
}
|
||||
|
||||
public ZipEntry nextElement() {
|
||||
return new MyZipEntry(window, iterator.next());
|
||||
return factory.makeEntry(window, iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ Avian_avian_SystemClassLoader_findVMClass
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_avian_SystemClassLoader_resourceExists
|
||||
Avian_avian_SystemClassLoader_resourceURLPrefix
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
@ -79,13 +79,10 @@ Avian_avian_SystemClassLoader_resourceExists
|
||||
THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
unsigned length;
|
||||
bool r = static_cast<Finder*>(systemClassLoaderFinder(t, loader))->stat
|
||||
(RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile;
|
||||
const char* name = static_cast<Finder*>
|
||||
(systemClassLoaderFinder(t, loader))->urlPrefix(RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
// fprintf(stderr, "resource %s exists? %d\n", n, r);
|
||||
|
||||
return r;
|
||||
return name ? reinterpret_cast<uintptr_t>(makeString(t, "%s", name)) : 0;
|
||||
} else {
|
||||
throwNew(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ class Element {
|
||||
virtual System::Region* find(const char* name) = 0;
|
||||
virtual System::FileType stat(const char* name, unsigned* length,
|
||||
bool tryDirectory) = 0;
|
||||
virtual const char* urlPrefix() = 0;
|
||||
virtual void dispose() = 0;
|
||||
|
||||
Element* next;
|
||||
@ -123,7 +124,8 @@ class DirectoryElement: public Element {
|
||||
};
|
||||
|
||||
DirectoryElement(System* s, Allocator* allocator, const char* name):
|
||||
s(s), allocator(allocator), name(name)
|
||||
s(s), allocator(allocator), name(name),
|
||||
urlPrefix_(append(allocator, "file:", name, "/"))
|
||||
{ }
|
||||
|
||||
virtual Element::Iterator* iterator() {
|
||||
@ -157,14 +159,20 @@ class DirectoryElement: public Element {
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual const char* urlPrefix() {
|
||||
return urlPrefix_;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
allocator->free(name, strlen(name) + 1);
|
||||
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
|
||||
allocator->free(this, sizeof(*this));
|
||||
}
|
||||
|
||||
System* s;
|
||||
Allocator* allocator;
|
||||
const char* name;
|
||||
const char* urlPrefix_;
|
||||
};
|
||||
|
||||
class PointerRegion: public System::Region {
|
||||
@ -428,7 +436,9 @@ class JarElement: public Element {
|
||||
};
|
||||
|
||||
JarElement(System* s, Allocator* allocator, const char* name):
|
||||
s(s), allocator(allocator), name(name), region(0), index(0)
|
||||
s(s), allocator(allocator), name(name),
|
||||
urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0),
|
||||
region(0), index(0)
|
||||
{ }
|
||||
|
||||
JarElement(System* s, Allocator* allocator, const uint8_t* jarData,
|
||||
@ -436,6 +446,7 @@ class JarElement: public Element {
|
||||
s(s),
|
||||
allocator(allocator),
|
||||
name(0),
|
||||
urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0),
|
||||
region(new (allocator->allocate(sizeof(PointerRegion)))
|
||||
PointerRegion(s, allocator, jarData, jarLength)),
|
||||
index(JarIndex::open(s, allocator, region))
|
||||
@ -485,12 +496,17 @@ class JarElement: public Element {
|
||||
: System::TypeDoesNotExist);
|
||||
}
|
||||
|
||||
virtual const char* urlPrefix() {
|
||||
return urlPrefix_;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
dispose(sizeof(*this));
|
||||
}
|
||||
|
||||
virtual void dispose(unsigned size) {
|
||||
allocator->free(name, strlen(name) + 1);
|
||||
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
|
||||
if (index) {
|
||||
index->dispose();
|
||||
}
|
||||
@ -503,6 +519,7 @@ class JarElement: public Element {
|
||||
System* s;
|
||||
Allocator* allocator;
|
||||
const char* name;
|
||||
const char* urlPrefix_;
|
||||
System::Region* region;
|
||||
JarIndex* index;
|
||||
};
|
||||
@ -535,6 +552,10 @@ class BuiltinElement: public JarElement {
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char* urlPrefix() {
|
||||
return "resource:";
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
library->disposeAll();
|
||||
if (libraryName) {
|
||||
@ -769,6 +790,18 @@ class MyFinder: public Finder {
|
||||
return System::TypeDoesNotExist;
|
||||
}
|
||||
|
||||
virtual const char* urlPrefix(const char* name) {
|
||||
for (Element* e = path_; e; e = e->next) {
|
||||
unsigned length;
|
||||
System::FileType type = e->stat(name, &length, true);
|
||||
if (type != System::TypeDoesNotExist) {
|
||||
return e->urlPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual const char* path() {
|
||||
return pathString;
|
||||
}
|
||||
|
@ -167,6 +167,7 @@ class Finder {
|
||||
virtual System::FileType stat(const char* name,
|
||||
unsigned* length,
|
||||
bool tryDirectory = false) = 0;
|
||||
virtual const char* urlPrefix(const char* name) = 0;
|
||||
virtual const char* path() = 0;
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user