Skip to content
This repository has been archived by the owner on Feb 25, 2023. It is now read-only.

Commit

Permalink
Provide APIs to allow usage of cached ZipFileSystem instances
Browse files Browse the repository at this point in the history
Added JDK 11's zipfs implementation
  • Loading branch information
itsaky committed Aug 8, 2022
1 parent 5e86543 commit a3ce2d0
Show file tree
Hide file tree
Showing 24 changed files with 6,464 additions and 274 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public FileSystem getFileSystem(URI uri) {
}

// Checks that the given file is a UnixPath
static final ZipPath toZipPath(Path path) {
public static final ZipPath toZipPath(Path path) {
if (path == null)
throw new NullPointerException();
if (!(path instanceof ZipPath))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package com.sun.tools.javac.file;
package com.itsaky.androidide.zipfs2;

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.spi.FileSystemProvider;
import java.util.HashMap;

import com.itsaky.androidide.zipfs.ZipFileSystemProvider;
import javac.internal.jrtfs.JrtFileSystemProvider;

public class AndroidFsProvider {

// Can be overridden to provide custom implementation
public static AndroidFsProvider INSTANCE = new AndroidFsProvider();

public FileSystemProvider zipFsProvider () {
public FileSystemProvider zipFsProvider() {
return new ZipFileSystemProvider();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package com.itsaky.androidide.zipfs2;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NonWritableChannelException;
import java.nio.channels.SeekableByteChannel;
import java.util.Arrays;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ByteArrayChannel implements SeekableByteChannel {

private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
private byte buf[];

/*
* The current position of this channel.
*/
private int pos;

/*
* The index that is one greater than the last valid byte in the channel.
*/
private int last;

private boolean closed;
private boolean readonly;

/*
* Creates a {@code ByteArrayChannel} with size {@code sz}.
*/
ByteArrayChannel(int sz, boolean readonly) {
this.buf = new byte[sz];
this.pos = this.last = 0;
this.readonly = readonly;
}

/*
* Creates a ByteArrayChannel with its 'pos' at 0 and its 'last' at buf's end.
* Note: no defensive copy of the 'buf', used directly.
*/
ByteArrayChannel(byte[] buf, boolean readonly) {
this.buf = buf;
this.pos = 0;
this.last = buf.length;
this.readonly = readonly;
}

@Override
public boolean isOpen() {
return !closed;
}

@Override
public long position() throws IOException {
beginRead();
try {
ensureOpen();
return pos;
} finally {
endRead();
}
}

@Override
public SeekableByteChannel position(long pos) throws IOException {
beginWrite();
try {
ensureOpen();
if (pos < 0 || pos >= Integer.MAX_VALUE)
throw new IllegalArgumentException("Illegal position " + pos);
this.pos = Math.min((int)pos, last);
return this;
} finally {
endWrite();
}
}

@Override
public int read(ByteBuffer dst) throws IOException {
beginWrite();
try {
ensureOpen();
if (pos == last)
return -1;
int n = Math.min(dst.remaining(), last - pos);
dst.put(buf, pos, n);
pos += n;
return n;
} finally {
endWrite();
}
}

@Override
public SeekableByteChannel truncate(long size) throws IOException {
if (readonly)
throw new NonWritableChannelException();
ensureOpen();
throw new UnsupportedOperationException();
}

@Override
public int write(ByteBuffer src) throws IOException {
if (readonly)
throw new NonWritableChannelException();
beginWrite();
try {
ensureOpen();
int n = src.remaining();
ensureCapacity(pos + n);
src.get(buf, pos, n);
pos += n;
if (pos > last) {
last = pos;
}
return n;
} finally {
endWrite();
}
}

@Override
public long size() throws IOException {
beginRead();
try {
ensureOpen();
return last;
} finally {
endRead();
}
}

@Override
public void close() throws IOException {
if (closed)
return;
beginWrite();
try {
closed = true;
buf = null;
pos = 0;
last = 0;
} finally {
endWrite();
}
}

/**
* Creates a newly allocated byte array. Its size is the current
* size of this channel and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this channel, as a byte array.
*/
public byte[] toByteArray() {
beginRead();
try {
// avoid copy if last == bytes.length?
return Arrays.copyOf(buf, last);
} finally {
endRead();
}
}

private void ensureOpen() throws IOException {
if (closed)
throw new ClosedChannelException();
}

private final void beginWrite() {
rwlock.writeLock().lock();
}

private final void endWrite() {
rwlock.writeLock().unlock();
}

private final void beginRead() {
rwlock.readLock().lock();
}

private final void endRead() {
rwlock.readLock().unlock();
}

private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if (minCapacity - buf.length > 0) {
grow(minCapacity);
}
}

/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = buf.length;
int newCapacity = oldCapacity << 1;
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
buf = Arrays.copyOf(buf, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.itsaky.androidide.zipfs2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
*
* @author itsaky
*/
public class Collections2 {

public static <T> List<T> listOf(T... values) {
final List<T> result = new ArrayList<>();
if (values == null) {
return result;
}
result.addAll(Arrays.asList(values));
return result;
}

public static <T> Set<T> setOf(T... values) {
final Set<T> result = new HashSet<>();
if (values == null) {
return result;
}
result.addAll(Arrays.asList(values));
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package com.itsaky.androidide.zipfs2;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;

public class JarFileSystemProvider extends ZipFileSystemProvider {

@Override
public String getScheme() {
return "jar";
}

@Override
protected Path uriToPath(URI uri) {
String scheme = uri.getScheme();
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
}
try {
String uristr = uri.toString();
int end = uristr.indexOf("!/");
uristr = uristr.substring(4, (end == -1) ? uristr.length() : end);
uri = new URI(uristr);
return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
.toAbsolutePath();
} catch (URISyntaxException e) {
throw new AssertionError(e); //never thrown
}
}

@Override
public Path getPath(URI uri) {
FileSystem fs = getFileSystem(uri);
String path = uri.getFragment();
if (path == null) {
String uristr = uri.toString();
int off = uristr.indexOf("!/");
if (off != -1)
path = uristr.substring(off + 2);
}
if (path != null)
return fs.getPath(path);
throw new IllegalArgumentException("URI: "
+ uri
+ " does not contain path fragment ex. jar:///c:/foo.zip!/BAR");
}
}
Loading

0 comments on commit a3ce2d0

Please sign in to comment.