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

View File

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

View File

@ -43,6 +43,18 @@ public class TypeHeader extends HeaderBlock{
addChild(entriesStart);
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
public int getMinimumSize(){
@ -77,6 +89,8 @@ public class TypeHeader extends HeaderBlock{
+", config=" + getConfig() + '}';
}
private static final byte FLAG_SPARSE = 0x1;
//typeHeader.countBytes() - getConfig().countBytes() + ResConfig.SIZE_16
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();
}
}