
com.reandroid.arsc.io.BlockReader Maven / Gradle / Ivy
/*
* 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.arsc.io;
import com.reandroid.arsc.header.InfoHeader;
import com.reandroid.arsc.header.SpecHeader;
import com.reandroid.arsc.header.TypeHeader;
import java.io.*;
public class BlockReader extends InputStream {
private final Object mLock=new Object();
private byte[] BUFFER;
private final int mStart;
private final int mLength;
private int mPosition;
private boolean mIsClosed;
private int mMark;
public BlockReader(byte[] buffer, int start, int length) {
this.BUFFER=buffer;
this.mStart=start;
this.mLength=length;
this.mPosition =0;
}
public BlockReader(byte[] buffer) {
this(buffer, 0, buffer.length);
}
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));
}
public int readUnsignedShort() throws IOException {
return 0x0000ffff & readShort();
}
public short readShort() throws IOException {
int pos = getPosition();
byte[] bts = new byte[2];
readFully(bts);
seek(pos);
return toShort(bts, 0);
}
public SpecHeader readSpecHeader() throws IOException{
SpecHeader specHeader = new SpecHeader();
if(available() < specHeader.countBytes()){
return null;
}
int pos = getPosition();
specHeader.readBytes(this);
seek(pos);
return specHeader;
}
public TypeHeader readTypeHeader() throws IOException{
TypeHeader typeHeader = new TypeHeader(false);
if(available() < typeHeader.getMinimumSize()){
return null;
}
int pos = getPosition();
typeHeader.readBytes(this);
seek(pos);
return typeHeader;
}
public InfoHeader readHeaderBlock() throws IOException {
InfoHeader infoHeader = new InfoHeader();
if(available() < infoHeader.getMinimumSize()){
return null;
}
int pos = getPosition();
infoHeader.readBytes(this);
seek(pos);
return infoHeader;
}
public int searchNextIntPosition(int bytesOffset, int value){
if(mIsClosed || mPosition>=mLength){
return -1;
}
synchronized (mLock){
int actPos=mStart+mPosition+bytesOffset;
int max=available()/4;
for(int i=0;i this.mLength){
len = this.mLength - start;
}
start = start + this.mStart;
return new BlockReader(BUFFER, start, len);
}
public boolean isAvailable(){
if(mIsClosed){
return false;
}
return available()>0;
}
public void offset(int off){
int pos=getPosition()+off;
seek(pos);
}
public void seek(int relPos){
if(relPos<0){
relPos=0;
}else if(relPos>length()){
relPos=length();
}
setPosition(relPos);
}
private void setPosition(int pos){
if(pos==mPosition){
return;
}
synchronized (mLock){
mPosition=pos;
}
}
public int length(){
return mLength;
}
public byte[] readBytes(int len) throws IOException {
byte[] result=new byte[len];
if(len==0){
return result;
}
int len2=read(result);
if(len2<0){
throw new EOFException("Finished reading: "+ mPosition);
}
if(len==len2){
return result;
}
byte[] result2=new byte[len2];
System.arraycopy(result, 0, result2, 0, len2);
return result2;
}
public int readFully(byte[] bts) throws IOException{
return readFully(bts, 0, bts.length);
}
public int readFully(byte[] bts, int length) throws IOException{
if(length==0){
return 0;
}
return readFully(bts, 0, length);
}
public int readFully(byte[] bts, int start, int length) throws IOException {
if(length==0){
return 0;
}
if(mIsClosed){
throw new IOException("Stream is closed");
}
if(mPosition>=mLength){
throw new EOFException("Finished reading: "+mPosition);
}
int len=bts.length;
if(length=mLength){
i++;
break;
}
}
return i;
}
}
public int getPosition(){
return mPosition;
}
public int getActualPosition(){
return mStart + mPosition;
}
public int getStartPosition(){
return mStart;
}
@Override
public int read() throws IOException {
if(mIsClosed){
throw new IOException("Stream is closed");
}
int i=mPosition;
if(i>=mLength){
throw new EOFException("Finished reading: "+i);
}
synchronized (mLock){
int actPos=mStart+i;
int val=BUFFER[actPos] & 0xff;
mPosition++;
return val;
}
}
@Override
public void mark(int pos){
mMark=pos;
}
@Override
public int available(){
return mLength-mPosition;
}
@Override
public void reset() throws IOException{
if(mIsClosed){
throw new IOException("Can not reset stream is closed");
}
mPosition=mMark;
}
@Override
public void close(){
mIsClosed=true;
BUFFER=null;
mMark=0;
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName());
builder.append(": ");
if(mIsClosed){
builder.append("Closed");
}else{
int av=available();
if(av==0){
builder.append("Finished: ");
builder.append(getPosition());
}else {
if(mStart>0){
builder.append("START=");
builder.append(mStart);
builder.append(", ACTUAL=");
builder.append(getActualPosition());
builder.append(", ");
}
builder.append("POS=");
builder.append(getPosition());
builder.append(", available=");
builder.append(av);
}
}
return builder.toString();
}
private static byte[] loadBuffer(File file) throws IOException {
FileInputStream in=new FileInputStream(file);
byte[] result = loadBuffer(in);
in.close();
return result;
}
private static byte[] loadBuffer(InputStream in) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buff=new byte[40960];
int len;
while((len=in.read(buff))>0){
outputStream.write(buff, 0, len);
}
if(in instanceof FileInputStream){
in.close();
}
outputStream.close();
return outputStream.toByteArray();
}
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 InfoHeader readHeaderBlock(File file) throws IOException{
return InfoHeader.readHeaderBlock(file);
}
public static InfoHeader readHeaderBlock(InputStream inputStream) throws IOException{
return InfoHeader.readHeaderBlock(inputStream);
}
public static InfoHeader readHeaderBlock(byte[] bytes) throws IOException{
return InfoHeader.readHeaderBlock(bytes);
}
private static final int MAX_FILE_SIZE = 1024 * 1000 * 40;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy