improve input stream read performance

This commit is contained in:
REAndroid 2023-01-15 07:23:44 -05:00
parent 2c9c0d1ba6
commit 74aba3d8ff
5 changed files with 100 additions and 91 deletions

View File

@ -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;
} }

View File

@ -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;
}
} }

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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();