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;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ByteArray;
import java.io.*;
@ -26,30 +25,25 @@ package com.reandroid.lib.arsc.chunk;
* handle any future android changes
* */
public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded {
private final ByteArray headerExtra;
private final ByteArray body;
public UnknownChunk() {
super(INITIAL_CHUNK_TYPE, 1);
this.headerExtra = new ByteArray();
this.body = new ByteArray();
addToHeader(this.headerExtra);
addChild(body);
setHeaderLoaded(this);
}
public ByteArray getBody(){
return body;
}
@Override
public void onChunkTypeLoaded(short type) {
}
@Override
public void onHeaderSizeLoaded(int headerSize) {
int extraSize = headerSize - 8;
this.headerExtra.setSize(extraSize);
}
@Override
public void onChunkSizeLoaded(int headerSize, int chunkSize) {
int bodySize = chunkSize - headerSize;
this.body.setSize(bodySize);
getBody().setSize(chunkSize - headerSize);
}
@Override
@ -68,18 +62,25 @@ public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded
}
return os.toByteArray();
}
public void readBytes(File file) throws IOException{
BlockReader reader=new BlockReader(file);
super.readBytes(reader);
public int readBytes(File file) throws IOException{
FileInputStream inputStream=new FileInputStream(file);
int result=readBytes(inputStream);
inputStream.close();
return result;
}
public void readBytes(InputStream inputStream) throws IOException{
BlockReader reader=new BlockReader(inputStream);
super.readBytes(reader);
public int readBytes(InputStream inputStream) throws IOException{
int result;
result=getHeaderBlock().readBytes(inputStream);
result+=getBody().readBytes(inputStream);
super.notifyBlockLoad();
return result;
}
public final int writeBytes(File file) throws IOException{
File dir=file.getParentFile();
if(dir!=null && !dir.exists()){
dir.mkdirs();
if(dir.mkdirs()){
throw new IOException("Can not create directory: "+dir);
}
}
OutputStream outputStream=new FileOutputStream(file);
int length = super.writeBytes(outputStream);
@ -88,15 +89,10 @@ public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded
}
@Override
public String toString(){
HeaderBlock headerBlock = getHeaderBlock();
return getClass().getSimpleName()
+"{ type="+String.format("0x%04x", headerBlock.getType())
+", chunkSize="+headerBlock.getChunkSize()
+", headerExtra="+headerExtra.size()
+", body="+body.size()+"}";
return getHeaderBlock()
+" {Body="+getBody().size()+"}";
}
// This value must not exist is ChunkType enum list
private static final short INITIAL_CHUNK_TYPE = 0x0207;
private static final short INITIAL_CHUNK_TYPE = 0x0000;
}

View File

@ -15,55 +15,12 @@
*/
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;
/**No importance of this class, to be removed latter*/
@Deprecated
public class AnyHeader extends HeaderBlock{
public AnyHeader() {
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;
import com.reandroid.lib.arsc.base.BlockContainer;
import com.reandroid.lib.arsc.chunk.ChunkType;
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.io.BlockLoad;
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.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad {
private final ShortItem mType;
@ -99,6 +106,46 @@ import java.io.IOException;
int count=parent.countBytes();
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
public void onReadBytes(BlockReader reader) throws IOException {
int start=reader.getPosition();
@ -162,7 +209,7 @@ import java.io.IOException;
builder.append(type.toString());
}else {
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(getHeaderSize());
@ -172,6 +219,18 @@ import java.io.IOException;
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{
void onChunkTypeLoaded(short type);
void onHeaderSizeLoaded(int headerSize);

View File

@ -15,7 +15,6 @@
*/
package com.reandroid.lib.arsc.io;
import com.reandroid.lib.arsc.header.AnyHeader;
import com.reandroid.lib.arsc.header.HeaderBlock;
import java.io.*;
@ -309,15 +308,10 @@ import java.io.*;
}
return buff;
}
public static AnyHeader readHeaderBlock(File file) throws IOException{
InputStream inputStream=new FileInputStream(file);
AnyHeader anyHeader = readHeaderBlock(inputStream);
inputStream.close();
return anyHeader;
public static HeaderBlock readHeaderBlock(File file) throws IOException{
return HeaderBlock.readHeaderBlock(file);
}
public static AnyHeader readHeaderBlock(InputStream inputStream) throws IOException{
AnyHeader anyHeader=new AnyHeader();
anyHeader.readBytes(inputStream);
return anyHeader;
public static HeaderBlock readHeaderBlock(InputStream inputStream) throws IOException{
return HeaderBlock.readHeaderBlock(inputStream);
}
}

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.TableStringArray;
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.item.IntegerArray;
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 {
AnyHeader tableHeader = BlockReader.readHeaderBlock(inputStream);
HeaderBlock tableHeader = HeaderBlock.readHeaderBlock(inputStream);
if(tableHeader.getChunkType()!=ChunkType.TABLE){
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){
throw new IOException("Not StringPool: "+poolHeader);
throw new IOException("Not StringPool chunk: " + poolChunk);
}
byte[] poolBytes = poolHeader.readChunkBytes(inputStream);
BlockReader blockReader = new BlockReader(poolBytes);
BlockReader blockReader = new BlockReader(poolChunk.getBytes());
TableStringPool stringPool = new TableStringPool(true);
stringPool.readBytes(blockReader);
blockReader.close();