manage input streams

This commit is contained in:
REAndroid
2023-01-09 07:42:30 -05:00
parent ac88f79acc
commit de7eb68486
9 changed files with 169 additions and 75 deletions

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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