java/com/facebook/soloader/ElfZipFileChannel.java (106 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.soloader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.annotation.Nullable;
public class ElfZipFileChannel implements ElfByteChannel {
private @Nullable InputStream mIs;
private final ZipEntry mZipEntry;
private final ZipFile mZipFile;
private final long mLength;
private boolean mOpened;
private long mPos;
public ElfZipFileChannel(ZipFile zipFile, ZipEntry zipEntry) throws IOException {
mZipFile = zipFile;
mZipEntry = zipEntry;
mOpened = true;
mPos = 0;
mLength = mZipEntry.getSize();
mIs = mZipFile.getInputStream(mZipEntry);
if (mIs == null) {
throw new IOException(mZipEntry.getName() + "'s InputStream is null");
}
}
@Override
public long position() throws IOException {
return mPos;
}
@Override
public ElfByteChannel position(long newPosition) throws IOException {
if (mIs == null) {
throw new IOException(mZipEntry.getName() + "'s InputStream is null");
}
if (newPosition == mPos) {
return this;
}
if (newPosition > mLength) {
newPosition = mLength;
}
if (newPosition >= mPos) {
mIs.skip(newPosition - mPos);
} else {
mIs.close();
mIs = mZipFile.getInputStream(mZipEntry);
if (mIs == null) {
throw new IOException(mZipEntry.getName() + "'s InputStream is null");
}
mIs.skip(newPosition);
}
mPos = newPosition;
return this;
}
/**
* Reads a sequence of bytes from this channel into the given buffer. Bytes are read starting at
* this channel's current file position, and then the file position is updated with the number of
* bytes actually read.
*
* @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
*/
@Override
public int read(ByteBuffer dst) throws IOException {
return read(dst, mPos);
}
/**
* Reads a sequence of bytes from this channel into the given buffer, starting at the given file
* position.
*
* <p>N.B. The file position is updated with the number of bytes actually read. It's different
* from <a
* href="https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#read(java.nio.ByteBuffer,%20long)">FileChannel.html#read(java.nio.ByteBuffer,
* long)</a>.
*
* @return The number of bytes read, possibly zero, or -1 if the given position is greater than or
* equal to the file's current size
*/
@Override
public int read(ByteBuffer dst, long position) throws IOException {
if (mIs == null) {
throw new IOException("InputStream is null");
}
int wanted = dst.remaining();
long possible = mLength - position;
if (possible <= 0) {
return -1;
}
if (wanted > (int) possible) {
wanted = (int) possible;
}
position(position);
if (dst.hasArray()) {
mIs.read(dst.array(), 0, wanted);
dst.position(dst.position() + wanted);
} else {
byte[] bytes = new byte[wanted];
mIs.read(bytes, 0, wanted);
dst.put(bytes, 0, wanted);
}
mPos += wanted;
return wanted;
}
@Override
public long size() throws IOException {
return mLength;
}
@Override
public ElfByteChannel truncate(long size) throws IOException {
throw new UnsupportedOperationException("ElfZipFileChannel doesn't support truncate");
}
@Override
public int write(ByteBuffer src) throws IOException {
// Readonly byte channel
throw new UnsupportedOperationException("ElfZipFileChannel doesn't support write");
}
@Override
public boolean isOpen() {
return mOpened;
}
@Override
public void close() throws IOException {
if (mIs != null) {
mIs.close();
mOpened = false;
}
}
}