mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-03 15:44:27 +02:00
improve input stream read performance
This commit is contained in:
parent
2c9c0d1ba6
commit
74aba3d8ff
@ -16,7 +16,6 @@
|
|||||||
package com.reandroid.lib.arsc.chunk;
|
package com.reandroid.lib.arsc.chunk;
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
|
||||||
import com.reandroid.lib.arsc.item.ByteArray;
|
import com.reandroid.lib.arsc.item.ByteArray;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -26,30 +25,25 @@ package com.reandroid.lib.arsc.chunk;
|
|||||||
* handle any future android changes
|
* handle any future android changes
|
||||||
* */
|
* */
|
||||||
public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded {
|
public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded {
|
||||||
private final ByteArray headerExtra;
|
|
||||||
private final ByteArray body;
|
private final ByteArray body;
|
||||||
public UnknownChunk() {
|
public UnknownChunk() {
|
||||||
super(INITIAL_CHUNK_TYPE, 1);
|
super(INITIAL_CHUNK_TYPE, 1);
|
||||||
this.headerExtra = new ByteArray();
|
|
||||||
this.body = new ByteArray();
|
this.body = new ByteArray();
|
||||||
|
|
||||||
addToHeader(this.headerExtra);
|
|
||||||
addChild(body);
|
addChild(body);
|
||||||
|
|
||||||
setHeaderLoaded(this);
|
setHeaderLoaded(this);
|
||||||
}
|
}
|
||||||
|
public ByteArray getBody(){
|
||||||
|
return body;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onChunkTypeLoaded(short type) {
|
public void onChunkTypeLoaded(short type) {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onHeaderSizeLoaded(int headerSize) {
|
public void onHeaderSizeLoaded(int headerSize) {
|
||||||
int extraSize = headerSize - 8;
|
|
||||||
this.headerExtra.setSize(extraSize);
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onChunkSizeLoaded(int headerSize, int chunkSize) {
|
public void onChunkSizeLoaded(int headerSize, int chunkSize) {
|
||||||
int bodySize = chunkSize - headerSize;
|
getBody().setSize(chunkSize - headerSize);
|
||||||
this.body.setSize(bodySize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,18 +62,25 @@ public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded
|
|||||||
}
|
}
|
||||||
return os.toByteArray();
|
return os.toByteArray();
|
||||||
}
|
}
|
||||||
public void readBytes(File file) throws IOException{
|
public int readBytes(File file) throws IOException{
|
||||||
BlockReader reader=new BlockReader(file);
|
FileInputStream inputStream=new FileInputStream(file);
|
||||||
super.readBytes(reader);
|
int result=readBytes(inputStream);
|
||||||
|
inputStream.close();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
public void readBytes(InputStream inputStream) throws IOException{
|
public int readBytes(InputStream inputStream) throws IOException{
|
||||||
BlockReader reader=new BlockReader(inputStream);
|
int result;
|
||||||
super.readBytes(reader);
|
result=getHeaderBlock().readBytes(inputStream);
|
||||||
|
result+=getBody().readBytes(inputStream);
|
||||||
|
super.notifyBlockLoad();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
public final int writeBytes(File file) throws IOException{
|
public final int writeBytes(File file) throws IOException{
|
||||||
File dir=file.getParentFile();
|
File dir=file.getParentFile();
|
||||||
if(dir!=null && !dir.exists()){
|
if(dir!=null && !dir.exists()){
|
||||||
dir.mkdirs();
|
if(dir.mkdirs()){
|
||||||
|
throw new IOException("Can not create directory: "+dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OutputStream outputStream=new FileOutputStream(file);
|
OutputStream outputStream=new FileOutputStream(file);
|
||||||
int length = super.writeBytes(outputStream);
|
int length = super.writeBytes(outputStream);
|
||||||
@ -88,15 +89,10 @@ public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
HeaderBlock headerBlock = getHeaderBlock();
|
return getHeaderBlock()
|
||||||
return getClass().getSimpleName()
|
+" {Body="+getBody().size()+"}";
|
||||||
+"{ type="+String.format("0x%04x", headerBlock.getType())
|
|
||||||
+", chunkSize="+headerBlock.getChunkSize()
|
|
||||||
+", headerExtra="+headerExtra.size()
|
|
||||||
+", body="+body.size()+"}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This value must not exist is ChunkType enum list
|
private static final short INITIAL_CHUNK_TYPE = 0x0000;
|
||||||
private static final short INITIAL_CHUNK_TYPE = 0x0207;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,55 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.lib.arsc.header;
|
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.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.item.BlockItem;
|
|
||||||
import com.reandroid.lib.arsc.item.ByteArray;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
|
/**No importance of this class, to be removed latter*/
|
||||||
|
@Deprecated
|
||||||
public class AnyHeader extends HeaderBlock{
|
public class AnyHeader extends HeaderBlock{
|
||||||
public AnyHeader() {
|
public AnyHeader() {
|
||||||
super(ChunkType.NULL.ID);
|
super(ChunkType.NULL.ID);
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
while (length>0){
|
|
||||||
int len = inputStream.read(buffer, offset, length);
|
|
||||||
length=length-len;
|
|
||||||
offset=offset+len;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.lib.arsc.header;
|
package com.reandroid.lib.arsc.header;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.base.BlockContainer;
|
||||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.base.Block;
|
import com.reandroid.lib.arsc.base.Block;
|
||||||
|
import com.reandroid.lib.arsc.container.BlockList;
|
||||||
import com.reandroid.lib.arsc.container.ExpandableBlockContainer;
|
import com.reandroid.lib.arsc.container.ExpandableBlockContainer;
|
||||||
import com.reandroid.lib.arsc.io.BlockLoad;
|
import com.reandroid.lib.arsc.io.BlockLoad;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.lib.arsc.item.BlockItem;
|
||||||
import com.reandroid.lib.arsc.item.ByteArray;
|
import com.reandroid.lib.arsc.item.ByteArray;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
import com.reandroid.lib.arsc.item.ShortItem;
|
import com.reandroid.lib.arsc.item.ShortItem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad {
|
public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad {
|
||||||
private final ShortItem mType;
|
private final ShortItem mType;
|
||||||
@ -99,6 +106,46 @@ import java.io.IOException;
|
|||||||
int count=parent.countBytes();
|
int count=parent.countBytes();
|
||||||
setChunkSize(count);
|
setChunkSize(count);
|
||||||
}
|
}
|
||||||
|
/**Non buffering reader*/
|
||||||
|
public int readBytes(InputStream inputStream) throws IOException{
|
||||||
|
int result = onReadBytes(inputStream);
|
||||||
|
super.notifyBlockLoad();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private int onReadBytes(InputStream inputStream) throws IOException {
|
||||||
|
int readCount = readBytes(inputStream, this);
|
||||||
|
int difference = getHeaderSize() - readCount;
|
||||||
|
if(difference==0){
|
||||||
|
return readCount;
|
||||||
|
}
|
||||||
|
if(extraBytes.getParent()==null){
|
||||||
|
addChild(extraBytes);
|
||||||
|
}
|
||||||
|
extraBytes.setSize(difference);
|
||||||
|
readCount += extraBytes.readBytes(inputStream);
|
||||||
|
return readCount;
|
||||||
|
}
|
||||||
|
private int readBytes(InputStream inputStream, Block block) throws IOException{
|
||||||
|
int result=0;
|
||||||
|
if(block instanceof BlockItem){
|
||||||
|
result = ((BlockItem)block).readBytes(inputStream);
|
||||||
|
}else if(block instanceof BlockList){
|
||||||
|
List<? extends Block> childes=
|
||||||
|
((BlockList<? extends Block>) block).getChildes();
|
||||||
|
for(Block child:childes){
|
||||||
|
result+=readBytes(inputStream, child);
|
||||||
|
}
|
||||||
|
}else if(block instanceof BlockContainer){
|
||||||
|
Block[] childes =
|
||||||
|
((BlockContainer<? extends Block>) block).getChildes();
|
||||||
|
for(Block child:childes){
|
||||||
|
result+=readBytes(inputStream, child);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
throw new IOException("Can not read block type: "+block.getClass());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onReadBytes(BlockReader reader) throws IOException {
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
int start=reader.getPosition();
|
int start=reader.getPosition();
|
||||||
@ -155,14 +202,14 @@ import java.io.IOException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
short t= getType();
|
short t = getType();
|
||||||
ChunkType type= ChunkType.get(t);
|
ChunkType type = ChunkType.get(t);
|
||||||
StringBuilder builder=new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
if(type!=null){
|
if(type!=null){
|
||||||
builder.append(type.toString());
|
builder.append(type.toString());
|
||||||
}else {
|
}else {
|
||||||
builder.append("Unknown type=");
|
builder.append("Unknown type=");
|
||||||
builder.append(String.format("0x%02x", ((int)t)));
|
builder.append(String.format("0x%02x", (0xffff & t)));
|
||||||
}
|
}
|
||||||
builder.append("{Header=");
|
builder.append("{Header=");
|
||||||
builder.append(getHeaderSize());
|
builder.append(getHeaderSize());
|
||||||
@ -172,6 +219,18 @@ import java.io.IOException;
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HeaderBlock readHeaderBlock(File file) throws IOException{
|
||||||
|
InputStream inputStream = new FileInputStream(file);
|
||||||
|
HeaderBlock headerBlock = readHeaderBlock(inputStream);
|
||||||
|
inputStream.close();
|
||||||
|
return headerBlock;
|
||||||
|
}
|
||||||
|
public static HeaderBlock readHeaderBlock(InputStream inputStream) throws IOException {
|
||||||
|
HeaderBlock headerBlock=new HeaderBlock(ChunkType.NULL.ID);
|
||||||
|
headerBlock.readBytes(inputStream);
|
||||||
|
return headerBlock;
|
||||||
|
}
|
||||||
|
|
||||||
public interface HeaderLoaded{
|
public interface HeaderLoaded{
|
||||||
void onChunkTypeLoaded(short type);
|
void onChunkTypeLoaded(short type);
|
||||||
void onHeaderSizeLoaded(int headerSize);
|
void onHeaderSizeLoaded(int headerSize);
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.lib.arsc.io;
|
package com.reandroid.lib.arsc.io;
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.header.AnyHeader;
|
|
||||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -309,15 +308,10 @@ import java.io.*;
|
|||||||
}
|
}
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
public static AnyHeader readHeaderBlock(File file) throws IOException{
|
public static HeaderBlock readHeaderBlock(File file) throws IOException{
|
||||||
InputStream inputStream=new FileInputStream(file);
|
return HeaderBlock.readHeaderBlock(file);
|
||||||
AnyHeader anyHeader = readHeaderBlock(inputStream);
|
|
||||||
inputStream.close();
|
|
||||||
return anyHeader;
|
|
||||||
}
|
}
|
||||||
public static AnyHeader readHeaderBlock(InputStream inputStream) throws IOException{
|
public static HeaderBlock readHeaderBlock(InputStream inputStream) throws IOException{
|
||||||
AnyHeader anyHeader=new AnyHeader();
|
return HeaderBlock.readHeaderBlock(inputStream);
|
||||||
anyHeader.readBytes(inputStream);
|
|
||||||
return anyHeader;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ package com.reandroid.lib.arsc.pool;
|
|||||||
import com.reandroid.lib.arsc.array.StringArray;
|
import com.reandroid.lib.arsc.array.StringArray;
|
||||||
import com.reandroid.lib.arsc.array.TableStringArray;
|
import com.reandroid.lib.arsc.array.TableStringArray;
|
||||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.header.AnyHeader;
|
import com.reandroid.lib.arsc.chunk.UnknownChunk;
|
||||||
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
import com.reandroid.lib.arsc.item.IntegerArray;
|
import com.reandroid.lib.arsc.item.IntegerArray;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
@ -57,19 +58,21 @@ import java.io.InputStream;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads string pool from table block (resources.arsc)
|
* Loads string pool only from table block (resources.arsc) without
|
||||||
|
* loading other chunks
|
||||||
*/
|
*/
|
||||||
public static TableStringPool readFromTable(InputStream inputStream) throws IOException {
|
public static TableStringPool readFromTable(InputStream inputStream) throws IOException {
|
||||||
AnyHeader tableHeader = BlockReader.readHeaderBlock(inputStream);
|
HeaderBlock tableHeader = HeaderBlock.readHeaderBlock(inputStream);
|
||||||
if(tableHeader.getChunkType()!=ChunkType.TABLE){
|
if(tableHeader.getChunkType()!=ChunkType.TABLE){
|
||||||
throw new IOException("Not TableBlock: "+tableHeader);
|
throw new IOException("Not TableBlock: "+tableHeader);
|
||||||
}
|
}
|
||||||
AnyHeader poolHeader = BlockReader.readHeaderBlock(inputStream);
|
UnknownChunk poolChunk = new UnknownChunk();
|
||||||
|
poolChunk.readBytes(inputStream);
|
||||||
|
HeaderBlock poolHeader = poolChunk.getHeaderBlock();
|
||||||
if(poolHeader.getChunkType()!=ChunkType.STRING){
|
if(poolHeader.getChunkType()!=ChunkType.STRING){
|
||||||
throw new IOException("Not StringPool: "+poolHeader);
|
throw new IOException("Not StringPool chunk: " + poolChunk);
|
||||||
}
|
}
|
||||||
byte[] poolBytes = poolHeader.readChunkBytes(inputStream);
|
BlockReader blockReader = new BlockReader(poolChunk.getBytes());
|
||||||
BlockReader blockReader = new BlockReader(poolBytes);
|
|
||||||
TableStringPool stringPool = new TableStringPool(true);
|
TableStringPool stringPool = new TableStringPool(true);
|
||||||
stringPool.readBytes(blockReader);
|
stringPool.readBytes(blockReader);
|
||||||
blockReader.close();
|
blockReader.close();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user