mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-30 06:14:25 +02:00
scan LFH from mark supported input stream
This commit is contained in:
parent
06185e4fff
commit
c517505cbf
@ -17,6 +17,9 @@ package com.reandroid.archive2.block;
|
||||
|
||||
import com.reandroid.archive2.ZipSignature;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class LocalFileHeader extends CommonHeader {
|
||||
private DataDescriptor dataDescriptor;
|
||||
public LocalFileHeader(){
|
||||
@ -64,6 +67,15 @@ public class LocalFileHeader extends CommonHeader {
|
||||
lfh.setExtra(ceh.getExtra());
|
||||
return lfh;
|
||||
}
|
||||
|
||||
public static LocalFileHeader read(InputStream inputStream) throws IOException {
|
||||
LocalFileHeader localFileHeader = new LocalFileHeader();
|
||||
localFileHeader.readBytes(inputStream);
|
||||
if(localFileHeader.isValidSignature()){
|
||||
return localFileHeader;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static final int OFFSET_signature = 0;
|
||||
private static final int OFFSET_versionMadeBy = 4;
|
||||
private static final int OFFSET_platform = 5;
|
||||
|
@ -17,31 +17,32 @@ package com.reandroid.archive2.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class FileChannelInputStream extends InputStream {
|
||||
private final FileChannel fileChannel;
|
||||
private final long length;
|
||||
private long total;
|
||||
private final long totalLength;
|
||||
private long startOffset;
|
||||
private long position;
|
||||
private final byte[] buffer;
|
||||
private int pos;
|
||||
private int bufferPosition;
|
||||
private int bufferLength;
|
||||
|
||||
public FileChannelInputStream(FileChannel fileChannel, long length){
|
||||
public FileChannelInputStream(FileChannel fileChannel, long length, int bufferSize) throws IOException {
|
||||
this.fileChannel = fileChannel;
|
||||
this.length = length;
|
||||
int len = 1024 * 1000 * 100;
|
||||
if(length < len){
|
||||
len = (int) length;
|
||||
this.totalLength = length;
|
||||
if(length < bufferSize){
|
||||
bufferSize = (int) length;
|
||||
}
|
||||
this.buffer = new byte[len];
|
||||
this.bufferLength = len;
|
||||
this.pos = len;
|
||||
this.buffer = new byte[bufferSize];
|
||||
this.bufferLength = bufferSize;
|
||||
this.bufferPosition = bufferSize;
|
||||
this.startOffset = fileChannel.position();
|
||||
}
|
||||
|
||||
public FileChannel getFileChannel() {
|
||||
return fileChannel;
|
||||
public FileChannelInputStream(FileChannel fileChannel, long length) throws IOException {
|
||||
this(fileChannel, length, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -72,7 +73,7 @@ public class FileChannelInputStream extends InputStream {
|
||||
return result;
|
||||
}
|
||||
private int readBuffer(byte[] bytes, int offset, int length){
|
||||
int avail = bufferLength - pos;
|
||||
int avail = bufferLength - bufferPosition;
|
||||
if(avail == 0){
|
||||
return 0;
|
||||
}
|
||||
@ -80,29 +81,105 @@ public class FileChannelInputStream extends InputStream {
|
||||
if(read > avail){
|
||||
read = avail;
|
||||
}
|
||||
System.arraycopy(buffer, pos, bytes, offset, read);
|
||||
pos += read;
|
||||
total += read;
|
||||
System.arraycopy(buffer, bufferPosition, bytes, offset, read);
|
||||
bufferPosition += read;
|
||||
position += read;
|
||||
return read;
|
||||
}
|
||||
private void loadBuffer() throws IOException {
|
||||
byte[] buffer = this.buffer;
|
||||
if(this.pos < buffer.length){
|
||||
if(this.bufferPosition < bufferLength){
|
||||
return;
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
|
||||
bufferLength = fileChannel.read(byteBuffer);
|
||||
pos = 0;
|
||||
bufferPosition = 0;
|
||||
}
|
||||
private boolean isFinished(){
|
||||
return total >= length;
|
||||
return position >= totalLength;
|
||||
}
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
throw new IOException("Why one byte?");
|
||||
byte[] bytes = new byte[1];
|
||||
int read = read(bytes);
|
||||
if(read < 0){
|
||||
return read;
|
||||
}
|
||||
return bytes[0] & 0xff;
|
||||
}
|
||||
public long transferTo(OutputStream out) throws IOException{
|
||||
long transferred = 0;
|
||||
if(isFinished()){
|
||||
return transferred;
|
||||
}
|
||||
while (!isFinished()){
|
||||
loadBuffer();
|
||||
int offset = bufferPosition;
|
||||
int length = bufferLength - bufferPosition;
|
||||
if(length <= 0){
|
||||
break;
|
||||
}
|
||||
out.write(buffer, offset, length);
|
||||
bufferPosition += length;
|
||||
position += length;
|
||||
transferred += length;
|
||||
}
|
||||
return transferred;
|
||||
}
|
||||
@Override
|
||||
public void reset(){
|
||||
total = 0;
|
||||
public long skip(long amount) throws IOException {
|
||||
if(amount <= 0){
|
||||
return amount;
|
||||
}
|
||||
long remaining = amount;
|
||||
remaining = remaining - skipBuffer((int) remaining);
|
||||
if(remaining == 0){
|
||||
return amount;
|
||||
}
|
||||
long availableChannel = totalLength - position;
|
||||
if(availableChannel > remaining){
|
||||
availableChannel = remaining;
|
||||
}
|
||||
position += availableChannel;
|
||||
remaining = remaining - availableChannel;
|
||||
amount = amount - remaining;
|
||||
fileChannel.position(fileChannel.position() + amount);
|
||||
return amount;
|
||||
}
|
||||
private int skipBuffer(int amount){
|
||||
int availableBuffer = bufferLength - bufferPosition;
|
||||
if(availableBuffer > amount){
|
||||
availableBuffer = amount;
|
||||
}
|
||||
bufferPosition += availableBuffer;
|
||||
position += availableBuffer;
|
||||
return availableBuffer;
|
||||
}
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
position = 0;
|
||||
bufferPosition = bufferLength;
|
||||
fileChannel.position(startOffset);
|
||||
}
|
||||
@Override
|
||||
public int available(){
|
||||
return (int) (totalLength - position);
|
||||
}
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public synchronized void mark(int readLimit){
|
||||
if(readLimit < 0){
|
||||
readLimit = 0;
|
||||
}
|
||||
startOffset = readLimit;
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return position + " / " + totalLength;
|
||||
}
|
||||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 100;
|
||||
}
|
||||
|
@ -17,12 +17,11 @@ package com.reandroid.archive2.model;
|
||||
|
||||
import com.reandroid.archive2.block.*;
|
||||
import com.reandroid.archive2.block.ApkSignatureBlock;
|
||||
import com.reandroid.archive2.io.FileChannelInputStream;
|
||||
import com.reandroid.archive2.io.ZipInput;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -45,36 +44,36 @@ public class LocalFileDirectory {
|
||||
private void visitLocalFile(ZipInput zipInput) throws IOException {
|
||||
List<LocalFileHeader> headerList = this.getHeaderList();
|
||||
long offset;
|
||||
int read;
|
||||
int index = 0;
|
||||
CentralFileDirectory centralFileDirectory = getCentralFileDirectory();
|
||||
long length = zipInput.getLength();
|
||||
FileChannelInputStream inputStream= (FileChannelInputStream) zipInput.getInputStream(0, length);
|
||||
FileChannel fileChannel = inputStream.getFileChannel();
|
||||
InputStream inputStream = zipInput.getInputStream(0, length);
|
||||
for(CentralEntryHeader ceh : centralFileDirectory.getHeaderList()){
|
||||
offset = ceh.getLocalRelativeOffset();
|
||||
fileChannel.position(offset);
|
||||
LocalFileHeader lfh = new LocalFileHeader();
|
||||
lfh.readBytes(inputStream);
|
||||
lfh.mergeZeroValues(ceh);
|
||||
inputStream.reset();
|
||||
offset = inputStream.skip(offset);
|
||||
LocalFileHeader lfh = LocalFileHeader.read(inputStream);
|
||||
if(lfh == null){
|
||||
throw new IOException("Error reading LFH at "
|
||||
+ offset + ", for CEH = " + ceh.getFileName());
|
||||
}
|
||||
offset = offset + lfh.countBytes();
|
||||
lfh.setFileOffset(offset);
|
||||
ceh.setFileOffset(offset);
|
||||
offset = inputStream.skip(lfh.getDataSize());
|
||||
lfh.mergeZeroValues(ceh);
|
||||
inputStream.skip(lfh.getDataSize());
|
||||
DataDescriptor dataDescriptor = null;
|
||||
if(lfh.hasDataDescriptor()){
|
||||
dataDescriptor = new DataDescriptor();
|
||||
read = dataDescriptor.readBytes(inputStream);
|
||||
if(read>0){
|
||||
offset += read;
|
||||
int read = dataDescriptor.readBytes(inputStream);
|
||||
if(read != dataDescriptor.countBytes()){
|
||||
dataDescriptor = null;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
lfh.setIndex(index);
|
||||
lfh.setDataDescriptor(dataDescriptor);
|
||||
lfh.setIndex(index);
|
||||
headerList.add(lfh);
|
||||
length = length - offset;
|
||||
inputStream.reset();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
private void visitApkSigBlock(ZipInput zipInput) throws IOException{
|
||||
|
Loading…
x
Reference in New Issue
Block a user