implement sparse type entry

This commit is contained in:
REAndroid 2023-04-26 21:57:10 +02:00
parent 1c810ece26
commit ecbb2fca2e
7 changed files with 213 additions and 8 deletions

View File

@ -0,0 +1,39 @@
/*
* 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.array;
import com.reandroid.arsc.base.BlockArray;
import com.reandroid.arsc.chunk.SparseTypeBlock;
public class SparseTypeBlockArray extends BlockArray<SparseTypeBlock> {
@Override
public SparseTypeBlock[] newInstance(int len) {
return new SparseTypeBlock[len];
}
@Override
public SparseTypeBlock newInstance() {
return new SparseTypeBlock();
}
@Override
protected void onRefreshed() {
}
public void merge(SparseTypeBlockArray sparse){
if(sparse == null || sparse == this){
return;
}
addAll(sparse.getChildes());
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.array;
import com.reandroid.arsc.base.BlockArray;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.value.SparseTypeEntry;
import java.io.IOException;
public class SparseTypeEntryArray extends BlockArray<SparseTypeEntry> {
@Override
public SparseTypeEntry[] newInstance(int len) {
return new SparseTypeEntry[len];
}
@Override
public SparseTypeEntry newInstance() {
return new SparseTypeEntry();
}
@Override
protected void onRefreshed() {
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
int count = reader.available() / 4;
setChildesCount(count);
super.onReadBytes(reader);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.chunk;
import com.reandroid.arsc.array.SparseTypeEntryArray;
import com.reandroid.arsc.header.TypeHeader;
import com.reandroid.arsc.value.SparseTypeEntry;
import java.util.Collection;
public class SparseTypeBlock extends Chunk<TypeHeader>{
private final SparseTypeEntryArray entryArray;
public SparseTypeBlock() {
super(new TypeHeader(), 1);
entryArray = new SparseTypeEntryArray();
addChild(entryArray);
getHeaderBlock().setSparse(true);
}
public Collection<SparseTypeEntry> listEntries(){
return getEntryArray().listItems();
}
public SparseTypeEntryArray getEntryArray() {
return entryArray;
}
@Override
protected void onChunkRefreshed() {
getHeaderBlock().setSparse(true);
}
}

View File

@ -116,9 +116,15 @@ public class PackageBody extends FixedBlockContainer {
private void readTypeBlock(BlockReader reader) throws IOException{ private void readTypeBlock(BlockReader reader) throws IOException{
TypeHeader typeHeader = reader.readTypeHeader(); TypeHeader typeHeader = reader.readTypeHeader();
SpecTypePair specTypePair = mSpecTypePairArray.getOrCreate(typeHeader.getId().get()); SpecTypePair specTypePair = mSpecTypePairArray.getOrCreate(typeHeader.getId().get());
if(typeHeader.isSparse()){
SparseTypeBlock sparseTypeBlock = specTypePair
.getSparseTypeBlockArray().createNext();
sparseTypeBlock.readBytes(reader);
}else {
TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext(); TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext();
typeBlock.readBytes(reader); typeBlock.readBytes(reader);
} }
}
private void readLibraryBlock(BlockReader reader) throws IOException{ private void readLibraryBlock(BlockReader reader) throws IOException{
LibraryBlock libraryBlock=new LibraryBlock(); LibraryBlock libraryBlock=new LibraryBlock();
libraryBlock.readBytes(reader); libraryBlock.readBytes(reader);

View File

@ -16,15 +16,14 @@
package com.reandroid.arsc.container; package com.reandroid.arsc.container;
import com.reandroid.arsc.array.EntryArray; import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.chunk.ChunkType; import com.reandroid.arsc.array.SparseTypeBlockArray;
import com.reandroid.arsc.chunk.*;
import com.reandroid.arsc.array.TypeBlockArray; import com.reandroid.arsc.array.TypeBlockArray;
import com.reandroid.arsc.base.Block; import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.base.BlockContainer; import com.reandroid.arsc.base.BlockContainer;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.SpecBlock;
import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.group.EntryGroup; import com.reandroid.arsc.group.EntryGroup;
import com.reandroid.arsc.header.HeaderBlock; import com.reandroid.arsc.header.HeaderBlock;
import com.reandroid.arsc.header.TypeHeader;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.TypeString; import com.reandroid.arsc.item.TypeString;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.Entry;
@ -40,18 +39,31 @@ public class SpecTypePair extends BlockContainer<Block>
private final Block[] mChildes; private final Block[] mChildes;
private final SpecBlock mSpecBlock; private final SpecBlock mSpecBlock;
private final TypeBlockArray mTypeBlockArray; private final TypeBlockArray mTypeBlockArray;
private final SparseTypeBlockArray sparseTypeBlockArray;
public SpecTypePair(SpecBlock specBlock, TypeBlockArray typeBlockArray){ public SpecTypePair(SpecBlock specBlock, TypeBlockArray typeBlockArray){
this.mSpecBlock = specBlock; this.mSpecBlock = specBlock;
this.mTypeBlockArray = typeBlockArray; this.mTypeBlockArray = typeBlockArray;
this.mChildes=new Block[]{specBlock, typeBlockArray}; this.sparseTypeBlockArray = new SparseTypeBlockArray();
this.mChildes=new Block[]{specBlock, typeBlockArray, sparseTypeBlockArray};
mSpecBlock.setIndex(0); mSpecBlock.setIndex(0);
mTypeBlockArray.setIndex(1); mTypeBlockArray.setIndex(1);
sparseTypeBlockArray.setIndex(2);
mSpecBlock.setParent(this); mSpecBlock.setParent(this);
mTypeBlockArray.setParent(this); mTypeBlockArray.setParent(this);
sparseTypeBlockArray.setParent(this);
} }
public SpecTypePair(){ public SpecTypePair(){
this(new SpecBlock(), new TypeBlockArray()); this(new SpecBlock(), new TypeBlockArray());
} }
public SparseTypeBlockArray getSparseTypeBlockArray() {
return sparseTypeBlockArray;
}
public Collection<SparseTypeBlock> listSparseTypeBlock(){
return sparseTypeBlockArray.listItems();
}
public Map<Integer, EntryGroup> createEntryGroups(){ public Map<Integer, EntryGroup> createEntryGroups(){
Map<Integer, EntryGroup> map = new HashMap<>(); Map<Integer, EntryGroup> map = new HashMap<>();
for(TypeBlock typeBlock:listTypeBlocks()){ for(TypeBlock typeBlock:listTypeBlocks()){
@ -211,7 +223,7 @@ public class SpecTypePair extends BlockContainer<Block>
} }
ChunkType chunkType=headerBlock.getChunkType(); ChunkType chunkType=headerBlock.getChunkType();
if(chunkType == ChunkType.TYPE){ if(chunkType == ChunkType.TYPE){
mTypeBlockArray.readBytes(reader); readTypeBlock(reader);
return; return;
} }
if(chunkType!=ChunkType.SPEC){ if(chunkType!=ChunkType.SPEC){
@ -219,6 +231,15 @@ public class SpecTypePair extends BlockContainer<Block>
} }
mSpecBlock.readBytes(reader); mSpecBlock.readBytes(reader);
} }
private void readTypeBlock(BlockReader reader) throws IOException {
TypeHeader typeHeader = reader.readTypeHeader();
if(typeHeader.isSparse()){
SparseTypeBlock sparseTypeBlock = sparseTypeBlockArray.createNext();
sparseTypeBlock.readBytes(reader);
return;
}
mTypeBlockArray.readBytes(reader);
}
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);
} }
@ -260,6 +281,7 @@ public class SpecTypePair extends BlockContainer<Block>
} }
getSpecBlock().merge(typePair.getSpecBlock()); getSpecBlock().merge(typePair.getSpecBlock());
getTypeBlockArray().merge(typePair.getTypeBlockArray()); getTypeBlockArray().merge(typePair.getTypeBlockArray());
getSparseTypeBlockArray().merge(typePair.getSparseTypeBlockArray());
} }
@Override @Override
public int compareTo(SpecTypePair specTypePair) { public int compareTo(SpecTypePair specTypePair) {

View File

@ -43,6 +43,18 @@ public class TypeHeader extends HeaderBlock{
addChild(entriesStart); addChild(entriesStart);
addChild(config); addChild(config);
} }
public boolean isSparse(){
return (getFlags().get() & FLAG_SPARSE) == FLAG_SPARSE;
}
public void setSparse(boolean sparse){
byte flag = getFlags().get();
if(sparse){
flag = (byte) (flag | FLAG_SPARSE);
}else {
flag = (byte) (flag & (~FLAG_SPARSE & 0xff));
}
getFlags().set(flag);
}
@Override @Override
public int getMinimumSize(){ public int getMinimumSize(){
@ -77,6 +89,8 @@ public class TypeHeader extends HeaderBlock{
+", config=" + getConfig() + '}'; +", config=" + getConfig() + '}';
} }
private static final byte FLAG_SPARSE = 0x1;
//typeHeader.countBytes() - getConfig().countBytes() + ResConfig.SIZE_16 //typeHeader.countBytes() - getConfig().countBytes() + ResConfig.SIZE_16
private static final int TYPE_MIN_SIZE = 36; private static final int TYPE_MIN_SIZE = 36;
} }

View File

@ -0,0 +1,40 @@
/*
* 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.value;
import com.reandroid.arsc.item.BlockItem;
public class SparseTypeEntry extends BlockItem {
public SparseTypeEntry() {
super(4);
}
public int getIdx(){
return getShort(getBytesInternal(), 0) & 0xffff;
}
public void setIdx(int idx){
putShort(getBytesInternal(), 0, (short) idx);
}
public int getOffset(){
return getShort(getBytesInternal(), 2) & 0xffff;
}
public void setOffset(int offset){
putShort(getBytesInternal(), 2, (short) offset);
}
@Override
public String toString(){
return "idx=" + getIdx() + ", offset=" + getOffset();
}
}