This commit is contained in:
REAndroid 2022-11-23 08:04:01 -05:00
parent 6c4d425a79
commit 4fe4657f9f
18 changed files with 120 additions and 52 deletions

View File

@ -2,7 +2,7 @@
apply plugin: 'java-library' apply plugin: 'java-library'
group 'com.reandroid.lib.arsc' group 'com.reandroid.lib.arsc'
version '1.0.1' version '1.0.2'
java { java {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8

View File

@ -4,8 +4,6 @@ import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.EntryBlock; import com.reandroid.lib.arsc.value.EntryBlock;
import java.util.Iterator;
public class EntryBlockArray extends OffsetBlockArray<EntryBlock> { public class EntryBlockArray extends OffsetBlockArray<EntryBlock> {
public EntryBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){ public EntryBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
@ -22,7 +20,9 @@ public class EntryBlockArray extends OffsetBlockArray<EntryBlock> {
if(entryBlock!=null){ if(entryBlock!=null){
return entryBlock; return entryBlock;
} }
ensureSize(entryId+1); int count=entryId+1;
ensureSize(count);
refreshCount();
return get(entryId); return get(entryId);
} }
public EntryBlock getEntry(short entryId){ public EntryBlock getEntry(short entryId){

View File

@ -105,7 +105,7 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
refreshCount(); refreshCount();
refreshStart(); refreshStart();
} }
private void refreshCount(){ void refreshCount(){
mItemCount.set(childesCount()); mItemCount.set(childesCount());
} }
private void refreshStart(){ private void refreshStart(){

View File

@ -5,9 +5,7 @@ import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.container.SpecTypePair; import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.value.EntryBlock; import com.reandroid.lib.arsc.value.EntryBlock;
import java.util.ArrayList; import java.util.*;
import java.util.Iterator;
import java.util.List;
public class SpecTypePairArray extends BlockArray<SpecTypePair> { public class SpecTypePairArray extends BlockArray<SpecTypePair> {
public SpecTypePairArray(){ public SpecTypePairArray(){
@ -114,4 +112,32 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair> {
protected void onRefreshed() { protected void onRefreshed() {
} }
@Override
protected void onPreRefreshRefresh(){
validateEntryCounts();
}
// For android API < 26, it is required to have equal entry count on all SpecTypePair
private void validateEntryCounts(){
Map<Byte, Integer> entryCountMap=mapHighestEntryCount();
for(Map.Entry<Byte, Integer> entry:entryCountMap.entrySet()){
byte id=entry.getKey();
int count=entry.getValue();
SpecTypePair pair=getPair(id);
pair.getSpecBlock().setEntryCount(count);
pair.getTypeBlockArray().setEntryCount(count);
}
}
private Map<Byte, Integer> mapHighestEntryCount(){
Map<Byte, Integer> results=new HashMap<>();
SpecTypePair[] childes=getChildes();
for (SpecTypePair pair:childes){
int count=pair.getHighestEntryCount();
byte id=pair.getTypeId();
Integer exist=results.get(id);
if(exist==null || count>exist){
results.put(id, count);
}
}
return results;
}
} }

View File

@ -9,6 +9,7 @@ import java.util.List;
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T>{ public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T>{
private boolean mUtf8; private boolean mUtf8;
public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart); super(offsets, itemCount, itemStart);
this.mUtf8=is_utf8; this.mUtf8=is_utf8;

View File

@ -7,6 +7,7 @@ import com.reandroid.lib.arsc.chunk.SpecBlock;
import com.reandroid.lib.arsc.chunk.TypeBlock; import com.reandroid.lib.arsc.chunk.TypeBlock;
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.io.BlockReader;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock; import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResConfig; import com.reandroid.lib.arsc.value.ResConfig;
@ -207,4 +208,28 @@ public class TypeBlockArray extends BlockArray<TypeBlock> {
typeBlock.readBytes(reader); typeBlock.readBytes(reader);
return reader.getPosition()>pos; return reader.getPosition()>pos;
} }
public int getHighestEntryCount(){
int result=0;
for(TypeBlock typeBlock:getChildes()){
int count=typeBlock.getEntryCount();
if(count>result){
result=count;
}
}
return result;
}
public void setEntryCount(int count){
for(TypeBlock typeBlock:getChildes()){
typeBlock.setEntryCount(count);
}
}
public TypeString getTypeString(){
for(TypeBlock typeBlock:getChildes()){
TypeString typeString=typeBlock.getTypeString();
if(typeString!=null){
return typeString;
}
}
return null;
}
} }

View File

@ -5,12 +5,17 @@ import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.TypeString; import com.reandroid.lib.arsc.item.TypeString;
public class TypeStringArray extends StringArray<TypeString> { public class TypeStringArray extends StringArray<TypeString> {
private int lastCreateIndex;
public TypeStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public TypeStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8); super(offsets, itemCount, itemStart, is_utf8);
} }
@Override @Override
public TypeString newInstance() { public TypeString newInstance() {
return new TypeString(isUtf8()); TypeString typeString=new TypeString(isUtf8());
//create default name
this.lastCreateIndex++;
typeString.set("type-"+lastCreateIndex);
return typeString;
} }
@Override @Override
public TypeString[] newInstance(int len) { public TypeString[] newInstance(int len) {

View File

@ -157,7 +157,7 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
int result=-1; int result=-1;
for(int i=0;i<len;i++){ for(int i=0;i<len;i++){
if(block==items[i]){ if(block==items[i]){
result=-1; result=i;
} }
} }
return result; return result;

View File

@ -20,12 +20,16 @@ public abstract class BlockContainer<T extends Block> extends Block{
parent=parent.getParent(); parent=parent.getParent();
} }
return result; return result;
}
protected void onPreRefreshRefresh(){
} }
protected abstract void onRefreshed(); protected abstract void onRefreshed();
public final void refresh(){ public final void refresh(){
if(isNull()){ if(isNull()){
return; return;
} }
onPreRefreshRefresh();
refreshChildes(); refreshChildes();
onRefreshed(); onRefreshed();
} }
@ -36,7 +40,7 @@ public abstract class BlockContainer<T extends Block> extends Block{
for(int i=0;i<max;i++){ for(int i=0;i<max;i++){
T item=childes[i]; T item=childes[i];
if(item instanceof BlockContainer){ if(item instanceof BlockContainer){
BlockContainer container=(BlockContainer)item; BlockContainer<?> container=(BlockContainer<?>)item;
container.refresh(); container.refresh();
} }
} }

View File

@ -8,6 +8,7 @@ import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.PackageName; import com.reandroid.lib.arsc.item.PackageName;
import com.reandroid.lib.arsc.item.ReferenceItem; import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.pool.SpecStringPool; import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool; import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.pool.TypeStringPool; import com.reandroid.lib.arsc.pool.TypeStringPool;

View File

@ -50,13 +50,6 @@ public class TableBlock extends BaseChunk {
refreshPackageCount(); refreshPackageCount();
} }
@Override
public int onWriteBytes(OutputStream stream) throws IOException{
int result=super.onWriteBytes(stream);
stream.flush();
stream.close();
return result;
}
public void readBytes(File file) throws IOException{ public void readBytes(File file) throws IOException{
BlockReader reader=new BlockReader(file); BlockReader reader=new BlockReader(file);
super.readBytes(reader); super.readBytes(reader);
@ -74,7 +67,9 @@ public class TableBlock extends BaseChunk {
dir.mkdirs(); dir.mkdirs();
} }
OutputStream outputStream=new FileOutputStream(file); OutputStream outputStream=new FileOutputStream(file);
return super.writeBytes(outputStream); int length = super.writeBytes(outputStream);
outputStream.close();
return length;
} }
@Override @Override

View File

@ -107,13 +107,6 @@ public class ResXmlBlock extends BaseChunk {
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {
}
@Override
public int onWriteBytes(OutputStream stream) throws IOException{
int result=super.onWriteBytes(stream);
stream.flush();
stream.close();
return result;
} }
public void readBytes(File file) throws IOException{ public void readBytes(File file) throws IOException{
BlockReader reader=new BlockReader(file); BlockReader reader=new BlockReader(file);
@ -132,7 +125,9 @@ public class ResXmlBlock extends BaseChunk {
dir.mkdirs(); dir.mkdirs();
} }
OutputStream outputStream=new FileOutputStream(file); OutputStream outputStream=new FileOutputStream(file);
return super.writeBytes(outputStream); int length = super.writeBytes(outputStream);
outputStream.close();
return length;
} }
public static boolean isResXmlBlock(File file){ public static boolean isResXmlBlock(File file){

View File

@ -9,6 +9,7 @@ import com.reandroid.lib.arsc.chunk.SpecBlock;
import com.reandroid.lib.arsc.chunk.TypeBlock; import com.reandroid.lib.arsc.chunk.TypeBlock;
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.io.BlockReader;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock; import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResConfig; import com.reandroid.lib.arsc.value.ResConfig;
@ -128,5 +129,15 @@ public class SpecTypePair extends BlockContainer<Block> {
private void readUnexpectedNonSpecBlock(BlockReader reader, HeaderBlock headerBlock) throws IOException{ private void readUnexpectedNonSpecBlock(BlockReader reader, HeaderBlock headerBlock) throws IOException{
throw new IOException("Unexpected block: "+headerBlock.toString()+", Should be: "+ChunkType.SPEC); throw new IOException("Unexpected block: "+headerBlock.toString()+", Should be: "+ChunkType.SPEC);
} }
public int getHighestEntryCount(){
int specEntryCount=getSpecBlock().getEntryCount();
int typeEntryCount=getTypeBlockArray().getHighestEntryCount();
if(specEntryCount>typeEntryCount){
return specEntryCount;
}
return typeEntryCount;
}
public TypeString getTypeString(){
return getTypeBlockArray().getTypeString();
}
} }

View File

@ -306,7 +306,9 @@ public class BlockReader extends InputStream {
private static byte[] loadBuffer(File file) throws IOException { private static byte[] loadBuffer(File file) throws IOException {
FileInputStream in=new FileInputStream(file); FileInputStream in=new FileInputStream(file);
return loadBuffer(in); byte[] result = loadBuffer(in);
in.close();
return result;
} }
private static byte[] loadBuffer(InputStream in) throws IOException { private static byte[] loadBuffer(InputStream in) throws IOException {
byte[] result=new byte[0]; byte[] result=new byte[0];

View File

@ -2,6 +2,7 @@ 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.TypeStringArray; import com.reandroid.lib.arsc.array.TypeStringArray;
import com.reandroid.lib.arsc.group.StringGroup;
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;
import com.reandroid.lib.arsc.item.TypeString; import com.reandroid.lib.arsc.item.TypeString;
@ -13,6 +14,12 @@ public class TypeStringPool extends BaseStringPool<TypeString> {
public TypeString getById(int id){ public TypeString getById(int id){
return super.get(id-1); return super.get(id-1);
} }
public TypeString getOrCreate(int typeId, String typeName){
getStringsArray().ensureSize(typeId);
TypeString typeString=getById(typeId);
typeString.set(typeName);
return typeString;
}
@Override @Override
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new TypeStringArray(offsets, itemCount, itemStart, is_utf8); return new TypeStringArray(offsets, itemCount, itemStart, is_utf8);

View File

@ -1,22 +1,14 @@
package com.reandroid.lib.arsc.value; package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.item.BlockItem; import com.reandroid.lib.arsc.item.BlockItem;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ReferenceItem; import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool;
import java.util.List;
public abstract class BaseResValue extends BlockItem { public abstract class BaseResValue extends BlockItem {
BaseResValue(int bytesLength){ BaseResValue(int bytesLength){
super(bytesLength); super(bytesLength);
} }
public EntryBlock getEntryBlock(){ public EntryBlock getEntryBlock(){
Block parent=getParent(); Block parent=getParent();
while(parent!=null){ while(parent!=null){
@ -27,7 +19,6 @@ public abstract class BaseResValue extends BlockItem {
} }
return null; return null;
} }
boolean removeSpecReference(ReferenceItem ref){ boolean removeSpecReference(ReferenceItem ref){
EntryBlock entryBlock=getEntryBlock(); EntryBlock entryBlock=getEntryBlock();
if(entryBlock==null){ if(entryBlock==null){
@ -56,15 +47,10 @@ public abstract class BaseResValue extends BlockItem {
} }
entryBlock.addTableReference(ref); entryBlock.addTableReference(ref);
} }
@Override @Override
public void onBytesChanged() { public void onBytesChanged() {
} }
int getInt(int offset){ int getInt(int offset){
byte[] bts = getBytesInternal(); byte[] bts = getBytesInternal();
return bts[offset] & 0xff | return bts[offset] & 0xff |
@ -83,7 +69,6 @@ public abstract class BaseResValue extends BlockItem {
bts[offset]= (byte) (val & 0xff); bts[offset]= (byte) (val & 0xff);
onBytesChanged(); onBytesChanged();
} }
void setShort(int offset, short val){ void setShort(int offset, short val){
if(val==getShort(offset)){ if(val==getShort(offset)){
return; return;

View File

@ -17,7 +17,7 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EntryBlock extends Block { public class EntryBlock extends Block{
private ShortItem mHeaderSize; private ShortItem mHeaderSize;
private ShortItem mFlags; private ShortItem mFlags;
private IntegerItem mSpecReference; private IntegerItem mSpecReference;
@ -189,9 +189,13 @@ public class EntryBlock extends Block {
public void setFlagComplex(boolean is_complex){ public void setFlagComplex(boolean is_complex){
if(is_complex){ if(is_complex){
setFlags(FLAG_COMPLEX); if(!isFlagsComplex()){
setFlags(FLAG_COMPLEX);
}
}else { }else {
setFlags(FLAG_INT); if(isFlagsComplex()){
setFlags(FLAG_INT);
}
} }
refreshHeaderSize(); refreshHeaderSize();
} }
@ -437,7 +441,14 @@ public class EntryBlock extends Block {
if(isNull()){ if(isNull()){
return 0; return 0;
} }
return 8+mResValue.countBytes(); /*
mHeaderSize -> 2 bytes
mFlags -> 2 bytes
mSpecReference -> 4 bytes
-------
Total = 8 bytes, thus this value is always fixed no need to re-count
*/
return 8 + mResValue.countBytes();
} }
@Override @Override
public void onCountUpTo(BlockCounter counter) { public void onCountUpTo(BlockCounter counter) {
@ -514,6 +525,7 @@ public class EntryBlock extends Block {
updatePackage(); updatePackage();
updateSpecRef(); updateSpecRef();
} }
@Override
public String toString(){ public String toString(){
StringBuilder builder=new StringBuilder(); StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName()); builder.append(getClass().getSimpleName());
@ -566,9 +578,10 @@ public class EntryBlock extends Block {
private final static short FLAG_COMPLEX_MASK = 0x0001; private final static short FLAG_COMPLEX_MASK = 0x0001;
private final static short FLAG_COMPLEX = 0x0003; private final static short FLAG_COMPLEX = 0x0001;
private final static short FLAG_INT = 0x0002; private final static short FLAG_INT = 0x0000;
private final static short HEADER_COMPLEX=0x0010; private final static short HEADER_COMPLEX=0x0010;
private final static short HEADER_INT=0x0008; private final static short HEADER_INT=0x0008;
} }

View File

@ -2,8 +2,6 @@ package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.decoder.ValueDecoder; import com.reandroid.lib.arsc.decoder.ValueDecoder;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ReferenceItem;
import java.io.IOException; import java.io.IOException;