mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-06-13 05:37:41 +02:00
manage input streams
This commit is contained in:
@ -269,8 +269,10 @@ public class ApkModule {
|
||||
}
|
||||
if((inputSource instanceof ZipEntrySource)
|
||||
||(inputSource instanceof FileInputSource)){
|
||||
|
||||
return TableStringPool.readFromTable(inputSource.openStream());
|
||||
InputStream inputStream = inputSource.openStream();
|
||||
TableStringPool stringPool = TableStringPool.readFromTable(inputStream);
|
||||
inputStream.close();
|
||||
return stringPool;
|
||||
}
|
||||
return getTableBlock().getTableStringPool();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import com.reandroid.lib.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class ResFile {
|
||||
@ -103,12 +104,15 @@ public class ResFile {
|
||||
}
|
||||
mBinXmlChecked=true;
|
||||
InputSource inputSource=getInputSource();
|
||||
if(inputSource instanceof XMLEncodeSource){
|
||||
if((inputSource instanceof XMLEncodeSource)
|
||||
|| (inputSource instanceof JsonXmlInputSource)){
|
||||
mBinXml=true;
|
||||
}else{
|
||||
try {
|
||||
mBinXml=ResXmlBlock.isResXmlBlock(getInputSource().openStream());
|
||||
} catch (IOException exception) {
|
||||
InputStream inputStream=getInputSource().openStream();
|
||||
mBinXml=ResXmlBlock.isResXmlBlock(inputStream);
|
||||
inputStream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
return mBinXml;
|
||||
|
@ -41,6 +41,9 @@ public abstract class Block {
|
||||
public final void setBlockLoad(BlockLoad blockLoad){
|
||||
mBlockLoad=blockLoad;
|
||||
}
|
||||
public void notifyBlockLoad() throws IOException {
|
||||
notifyBlockLoad(null);
|
||||
}
|
||||
private void notifyBlockLoad(BlockReader reader) throws IOException{
|
||||
BlockLoad blockLoad=mBlockLoad;
|
||||
if(blockLoad!=null){
|
||||
|
@ -309,8 +309,10 @@ package com.reandroid.lib.arsc.chunk.xml;
|
||||
}
|
||||
try {
|
||||
InputStream inputStream=new FileInputStream(file);
|
||||
return isResXmlBlock(inputStream);
|
||||
} catch (FileNotFoundException ignored) {
|
||||
boolean result = isResXmlBlock(inputStream);
|
||||
inputStream.close();
|
||||
return result;
|
||||
} catch (IOException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
86
src/main/java/com/reandroid/lib/arsc/header/AnyHeader.java
Normal file
86
src/main/java/com/reandroid/lib/arsc/header/AnyHeader.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* 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.reandroid.lib.arsc.header;
|
||||
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.item.BlockItem;
|
||||
import com.reandroid.lib.arsc.item.ByteArray;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class AnyHeader extends HeaderBlock{
|
||||
private final ByteArray extraBytes;
|
||||
public AnyHeader() {
|
||||
super(ChunkType.NULL.ID);
|
||||
this.extraBytes = new ByteArray();
|
||||
super.addChild(extraBytes);
|
||||
}
|
||||
public ByteArray getExtraBytes() {
|
||||
return extraBytes;
|
||||
}
|
||||
@Override
|
||||
void onHeaderSizeLoaded(int size){
|
||||
int max = 0x0000ffff;
|
||||
if(size > max){
|
||||
size=max;
|
||||
}else if(size<0){
|
||||
size=0;
|
||||
}
|
||||
extraBytes.setSize(size-8);
|
||||
super.onHeaderSizeLoaded(size);
|
||||
}
|
||||
public int readBytes(InputStream inputStream) throws IOException {
|
||||
int result=0;
|
||||
Block[] childes = getChildes();
|
||||
for(Block child:childes){
|
||||
if(child instanceof BlockItem){
|
||||
BlockItem blockItem=(BlockItem) child;
|
||||
result += blockItem.readBytes(inputStream);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public byte[] readChunkBytes(InputStream inputStream) throws IOException{
|
||||
int chunkSize = getChunkSize();
|
||||
int headerSize = getHeaderSize();
|
||||
if(chunkSize < 0 || chunkSize < headerSize){
|
||||
throw new IOException("Invalid chunk size: " + super.toString());
|
||||
}
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int length = chunkSize - headerSize;
|
||||
int offset = loadHeaderBytes(buffer);
|
||||
int readLength = inputStream.read(buffer, offset, length);
|
||||
if(readLength < length){
|
||||
throw new IOException("Read length is less than expected: length="
|
||||
+chunkSize+", read="+readLength);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
private int loadHeaderBytes(byte[] buffer){
|
||||
int index=0;
|
||||
Block[] childes = getChildes();
|
||||
for(Block child:childes){
|
||||
byte[] childBytes=child.getBytes();
|
||||
for(int i=0;i<childBytes.length;i++){
|
||||
buffer[index]=childBytes[i];
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
@ -95,16 +95,12 @@ import java.io.IOException;
|
||||
}
|
||||
@Override
|
||||
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
||||
HeaderLoaded headerLoaded = mHeaderLoaded;
|
||||
if(headerLoaded==null){
|
||||
return;
|
||||
}
|
||||
if(sender==this.mType){
|
||||
headerLoaded.onChunkTypeLoaded(mType.get());
|
||||
onChunkTypeLoaded(mType.get());
|
||||
}else if(sender==this.mHeaderSize){
|
||||
headerLoaded.onHeaderSizeLoaded(mHeaderSize.unsignedInt());
|
||||
onHeaderSizeLoaded(mHeaderSize.unsignedInt());
|
||||
}else if(sender==this.mChunkSize){
|
||||
headerLoaded.onChunkSizeLoaded(mHeaderSize.unsignedInt(),
|
||||
onChunkSizeLoaded(mHeaderSize.unsignedInt(),
|
||||
mChunkSize.get());
|
||||
}
|
||||
}
|
||||
@ -117,6 +113,24 @@ import java.io.IOException;
|
||||
protected void refreshChildes(){
|
||||
// Not required
|
||||
}
|
||||
void onChunkTypeLoaded(short chunkType){
|
||||
HeaderLoaded headerLoaded = mHeaderLoaded;
|
||||
if(headerLoaded!=null){
|
||||
headerLoaded.onChunkTypeLoaded(chunkType);
|
||||
}
|
||||
}
|
||||
void onHeaderSizeLoaded(int size){
|
||||
HeaderLoaded headerLoaded = mHeaderLoaded;
|
||||
if(headerLoaded!=null){
|
||||
headerLoaded.onHeaderSizeLoaded(size);
|
||||
}
|
||||
}
|
||||
void onChunkSizeLoaded(int headerSize, int chunkSize){
|
||||
HeaderLoaded headerLoaded = mHeaderLoaded;
|
||||
if(headerLoaded!=null){
|
||||
headerLoaded.onChunkSizeLoaded(headerSize, chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package com.reandroid.lib.arsc.io;
|
||||
|
||||
import com.reandroid.lib.arsc.header.AnyHeader;
|
||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
|
||||
public class BlockReader extends InputStream {
|
||||
public class BlockReader extends InputStream {
|
||||
private final Object mLock=new Object();
|
||||
private byte[] BUFFER;
|
||||
private final int mStart;
|
||||
@ -41,6 +41,9 @@ public class BlockReader extends InputStream {
|
||||
public BlockReader(InputStream in) throws IOException {
|
||||
this(loadBuffer(in));
|
||||
}
|
||||
public BlockReader(InputStream in, int length) throws IOException {
|
||||
this(loadBuffer(in, length));
|
||||
}
|
||||
public BlockReader(File file) throws IOException {
|
||||
this(loadBuffer(file));
|
||||
}
|
||||
@ -161,32 +164,6 @@ public class BlockReader extends InputStream {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
public int lengthUntilLastZero(int offset){
|
||||
if(mIsClosed || mPosition>=mLength){
|
||||
return 0;
|
||||
}
|
||||
synchronized (mLock){
|
||||
int actPos=mStart+mPosition-1;
|
||||
int max=available();
|
||||
int len=0;
|
||||
boolean zeroFound=false;
|
||||
for(int i=0;i<max;i++){
|
||||
actPos++;
|
||||
len++;
|
||||
if(i<offset){
|
||||
continue;
|
||||
}
|
||||
byte b=BUFFER[actPos];
|
||||
if(b==0){
|
||||
zeroFound=true;
|
||||
}else if(zeroFound){
|
||||
len--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
public int readFully(byte[] bts) throws IOException{
|
||||
return readFully(bts, 0, bts.length);
|
||||
}
|
||||
@ -197,25 +174,6 @@ public class BlockReader extends InputStream {
|
||||
return readFully(bts, 0, length);
|
||||
}
|
||||
|
||||
public int skipByteValues(byte b) throws IOException {
|
||||
if(mIsClosed){
|
||||
throw new IOException("Stream is closed");
|
||||
}
|
||||
if(mPosition>=mLength){
|
||||
throw new EOFException("Finished reading: "+mPosition);
|
||||
}
|
||||
synchronized (mLock){
|
||||
int i=0;
|
||||
while (mPosition<mLength){
|
||||
if(BUFFER[mStart+mPosition]!=b){
|
||||
return i;
|
||||
}
|
||||
mPosition++;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
public int readFully(byte[] bts, int start, int length) throws IOException {
|
||||
if(length==0){
|
||||
return 0;
|
||||
@ -339,15 +297,27 @@ public class BlockReader extends InputStream {
|
||||
outputStream.close();
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
public static HeaderBlock readHeaderBlock(File file) throws IOException{
|
||||
InputStream inputStream=new FileInputStream(file);
|
||||
return readHeaderBlock(inputStream);
|
||||
private static byte[] loadBuffer(InputStream in, int length) throws IOException {
|
||||
byte[] buff=new byte[length];
|
||||
if(length==0){
|
||||
return buff;
|
||||
}
|
||||
int readLength = in.read(buff, 0, length);
|
||||
if(readLength < length){
|
||||
throw new IOException("Read length is less than expected: length="
|
||||
+length+", read="+readLength);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
public static HeaderBlock readHeaderBlock(InputStream inputStream) throws IOException{
|
||||
byte[] buffer=new byte[8];
|
||||
inputStream.read(buffer, 0, 8);
|
||||
public static AnyHeader readHeaderBlock(File file) throws IOException{
|
||||
InputStream inputStream=new FileInputStream(file);
|
||||
AnyHeader anyHeader = readHeaderBlock(inputStream);
|
||||
inputStream.close();
|
||||
BlockReader reader=new BlockReader(buffer);
|
||||
return reader.readHeaderBlock();
|
||||
return anyHeader;
|
||||
}
|
||||
public static AnyHeader readHeaderBlock(InputStream inputStream) throws IOException{
|
||||
AnyHeader anyHeader=new AnyHeader();
|
||||
anyHeader.readBytes(inputStream);
|
||||
return anyHeader;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import com.reandroid.lib.arsc.base.BlockCounter;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public abstract class BlockItem extends Block {
|
||||
@ -104,4 +105,14 @@ public abstract class BlockItem extends Block {
|
||||
stream.write(getBytesInternal());
|
||||
return getBytesLength();
|
||||
}
|
||||
public int readBytes(InputStream inputStream) throws IOException {
|
||||
byte[] bts=getBytesInternal();
|
||||
if(bts==null || bts.length==0){
|
||||
return 0;
|
||||
}
|
||||
int readLength = inputStream.read(bts, 0, bts.length);
|
||||
onBytesChanged();
|
||||
super.notifyBlockLoad();
|
||||
return readLength;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ package com.reandroid.lib.arsc.pool;
|
||||
import com.reandroid.lib.arsc.array.StringArray;
|
||||
import com.reandroid.lib.arsc.array.TableStringArray;
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||
import com.reandroid.lib.arsc.header.AnyHeader;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
import com.reandroid.lib.arsc.item.IntegerArray;
|
||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||
@ -60,14 +60,16 @@ import java.io.InputStream;
|
||||
* Loads string pool from table block (resources.arsc)
|
||||
*/
|
||||
public static TableStringPool readFromTable(InputStream inputStream) throws IOException {
|
||||
//TODO: for better result, make blockReader to
|
||||
// load buffer only the size of string pool
|
||||
BlockReader blockReader = new BlockReader(inputStream);
|
||||
HeaderBlock tableHeader = blockReader.readHeaderBlock();
|
||||
AnyHeader tableHeader = BlockReader.readHeaderBlock(inputStream);
|
||||
if(tableHeader.getChunkType()!=ChunkType.TABLE){
|
||||
throw new IOException("Not TableBlock: "+tableHeader);
|
||||
}
|
||||
blockReader.seek(tableHeader.getHeaderSize());
|
||||
AnyHeader poolHeader = BlockReader.readHeaderBlock(inputStream);
|
||||
if(poolHeader.getChunkType()!=ChunkType.STRING){
|
||||
throw new IOException("Not StringPool: "+poolHeader);
|
||||
}
|
||||
byte[] poolBytes = poolHeader.readChunkBytes(inputStream);
|
||||
BlockReader blockReader = new BlockReader(poolBytes);
|
||||
TableStringPool stringPool = new TableStringPool(true);
|
||||
stringPool.readBytes(blockReader);
|
||||
blockReader.close();
|
||||
|
Reference in New Issue
Block a user