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 com.reandroid.archive2.ZipSignature;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class LocalFileHeader extends CommonHeader {
|
public class LocalFileHeader extends CommonHeader {
|
||||||
private DataDescriptor dataDescriptor;
|
private DataDescriptor dataDescriptor;
|
||||||
public LocalFileHeader(){
|
public LocalFileHeader(){
|
||||||
@ -64,6 +67,15 @@ public class LocalFileHeader extends CommonHeader {
|
|||||||
lfh.setExtra(ceh.getExtra());
|
lfh.setExtra(ceh.getExtra());
|
||||||
return lfh;
|
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_signature = 0;
|
||||||
private static final int OFFSET_versionMadeBy = 4;
|
private static final int OFFSET_versionMadeBy = 4;
|
||||||
private static final int OFFSET_platform = 5;
|
private static final int OFFSET_platform = 5;
|
||||||
|
@ -17,31 +17,32 @@ package com.reandroid.archive2.io;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
public class FileChannelInputStream extends InputStream {
|
public class FileChannelInputStream extends InputStream {
|
||||||
private final FileChannel fileChannel;
|
private final FileChannel fileChannel;
|
||||||
private final long length;
|
private final long totalLength;
|
||||||
private long total;
|
private long startOffset;
|
||||||
|
private long position;
|
||||||
private final byte[] buffer;
|
private final byte[] buffer;
|
||||||
private int pos;
|
private int bufferPosition;
|
||||||
private int bufferLength;
|
private int bufferLength;
|
||||||
|
|
||||||
public FileChannelInputStream(FileChannel fileChannel, long length){
|
public FileChannelInputStream(FileChannel fileChannel, long length, int bufferSize) throws IOException {
|
||||||
this.fileChannel = fileChannel;
|
this.fileChannel = fileChannel;
|
||||||
this.length = length;
|
this.totalLength = length;
|
||||||
int len = 1024 * 1000 * 100;
|
if(length < bufferSize){
|
||||||
if(length < len){
|
bufferSize = (int) length;
|
||||||
len = (int) length;
|
|
||||||
}
|
}
|
||||||
this.buffer = new byte[len];
|
this.buffer = new byte[bufferSize];
|
||||||
this.bufferLength = len;
|
this.bufferLength = bufferSize;
|
||||||
this.pos = len;
|
this.bufferPosition = bufferSize;
|
||||||
|
this.startOffset = fileChannel.position();
|
||||||
}
|
}
|
||||||
|
public FileChannelInputStream(FileChannel fileChannel, long length) throws IOException {
|
||||||
public FileChannel getFileChannel() {
|
this(fileChannel, length, DEFAULT_BUFFER_SIZE);
|
||||||
return fileChannel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,7 +73,7 @@ public class FileChannelInputStream extends InputStream {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
private int readBuffer(byte[] bytes, int offset, int length){
|
private int readBuffer(byte[] bytes, int offset, int length){
|
||||||
int avail = bufferLength - pos;
|
int avail = bufferLength - bufferPosition;
|
||||||
if(avail == 0){
|
if(avail == 0){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -80,29 +81,105 @@ public class FileChannelInputStream extends InputStream {
|
|||||||
if(read > avail){
|
if(read > avail){
|
||||||
read = avail;
|
read = avail;
|
||||||
}
|
}
|
||||||
System.arraycopy(buffer, pos, bytes, offset, read);
|
System.arraycopy(buffer, bufferPosition, bytes, offset, read);
|
||||||
pos += read;
|
bufferPosition += read;
|
||||||
total += read;
|
position += read;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
private void loadBuffer() throws IOException {
|
private void loadBuffer() throws IOException {
|
||||||
byte[] buffer = this.buffer;
|
byte[] buffer = this.buffer;
|
||||||
if(this.pos < buffer.length){
|
if(this.bufferPosition < bufferLength){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
|
||||||
bufferLength = fileChannel.read(byteBuffer);
|
bufferLength = fileChannel.read(byteBuffer);
|
||||||
pos = 0;
|
bufferPosition = 0;
|
||||||
}
|
}
|
||||||
private boolean isFinished(){
|
private boolean isFinished(){
|
||||||
return total >= length;
|
return position >= totalLength;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
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
|
@Override
|
||||||
public void reset(){
|
public long skip(long amount) throws IOException {
|
||||||
total = 0;
|
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.*;
|
||||||
import com.reandroid.archive2.block.ApkSignatureBlock;
|
import com.reandroid.archive2.block.ApkSignatureBlock;
|
||||||
import com.reandroid.archive2.io.FileChannelInputStream;
|
|
||||||
import com.reandroid.archive2.io.ZipInput;
|
import com.reandroid.archive2.io.ZipInput;
|
||||||
import com.reandroid.arsc.io.BlockReader;
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.FileChannel;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -45,36 +44,36 @@ public class LocalFileDirectory {
|
|||||||
private void visitLocalFile(ZipInput zipInput) throws IOException {
|
private void visitLocalFile(ZipInput zipInput) throws IOException {
|
||||||
List<LocalFileHeader> headerList = this.getHeaderList();
|
List<LocalFileHeader> headerList = this.getHeaderList();
|
||||||
long offset;
|
long offset;
|
||||||
int read;
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
CentralFileDirectory centralFileDirectory = getCentralFileDirectory();
|
CentralFileDirectory centralFileDirectory = getCentralFileDirectory();
|
||||||
long length = zipInput.getLength();
|
long length = zipInput.getLength();
|
||||||
FileChannelInputStream inputStream= (FileChannelInputStream) zipInput.getInputStream(0, length);
|
InputStream inputStream = zipInput.getInputStream(0, length);
|
||||||
FileChannel fileChannel = inputStream.getFileChannel();
|
|
||||||
for(CentralEntryHeader ceh : centralFileDirectory.getHeaderList()){
|
for(CentralEntryHeader ceh : centralFileDirectory.getHeaderList()){
|
||||||
offset = ceh.getLocalRelativeOffset();
|
offset = ceh.getLocalRelativeOffset();
|
||||||
fileChannel.position(offset);
|
inputStream.reset();
|
||||||
LocalFileHeader lfh = new LocalFileHeader();
|
offset = inputStream.skip(offset);
|
||||||
lfh.readBytes(inputStream);
|
LocalFileHeader lfh = LocalFileHeader.read(inputStream);
|
||||||
lfh.mergeZeroValues(ceh);
|
if(lfh == null){
|
||||||
|
throw new IOException("Error reading LFH at "
|
||||||
|
+ offset + ", for CEH = " + ceh.getFileName());
|
||||||
|
}
|
||||||
offset = offset + lfh.countBytes();
|
offset = offset + lfh.countBytes();
|
||||||
lfh.setFileOffset(offset);
|
lfh.setFileOffset(offset);
|
||||||
ceh.setFileOffset(offset);
|
ceh.setFileOffset(offset);
|
||||||
offset = inputStream.skip(lfh.getDataSize());
|
lfh.mergeZeroValues(ceh);
|
||||||
|
inputStream.skip(lfh.getDataSize());
|
||||||
DataDescriptor dataDescriptor = null;
|
DataDescriptor dataDescriptor = null;
|
||||||
if(lfh.hasDataDescriptor()){
|
if(lfh.hasDataDescriptor()){
|
||||||
dataDescriptor = new DataDescriptor();
|
dataDescriptor = new DataDescriptor();
|
||||||
read = dataDescriptor.readBytes(inputStream);
|
int read = dataDescriptor.readBytes(inputStream);
|
||||||
if(read>0){
|
if(read != dataDescriptor.countBytes()){
|
||||||
offset += read;
|
dataDescriptor = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
|
||||||
lfh.setIndex(index);
|
|
||||||
lfh.setDataDescriptor(dataDescriptor);
|
lfh.setDataDescriptor(dataDescriptor);
|
||||||
|
lfh.setIndex(index);
|
||||||
headerList.add(lfh);
|
headerList.add(lfh);
|
||||||
length = length - offset;
|
index++;
|
||||||
inputStream.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void visitApkSigBlock(ZipInput zipInput) throws IOException{
|
private void visitApkSigBlock(ZipInput zipInput) throws IOException{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user