full implementation of SPARSE type entries

This commit is contained in:
REAndroid 2023-04-27 19:12:39 +02:00
parent c239585091
commit 21569db1f3
29 changed files with 1008 additions and 946 deletions

View File

@ -15,7 +15,6 @@
*/ */
package com.reandroid.arsc.array; package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.Entry;
import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONConvert;
@ -26,9 +25,32 @@ import java.util.Iterator;
public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<JSONArray> { public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<JSONArray> {
public EntryArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){ public EntryArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super(offsets, itemCount, itemStart); super(offsets, itemCount, itemStart);
} }
public int getHighestEntryId(){
if(isSparse()){
return ((SparseOffsetsArray) getOffsetArray()).getHighestId();
}
return childesCount();
}
public int getEntryId(int index){
OffsetArray offsetArray = getOffsetArray();
if(offsetArray instanceof SparseOffsetsArray){
return ((SparseOffsetsArray) offsetArray).getIdx(index);
}
return index;
}
public int getEntryIndex(int entryId){
OffsetArray offsetArray = getOffsetArray();
if(offsetArray instanceof SparseOffsetsArray){
return ((SparseOffsetsArray) offsetArray).indexOf(entryId);
}
return entryId;
}
public boolean isSparse(){
return super.getOffsetArray() instanceof SparseOffsetsArray;
}
public void destroy(){ public void destroy(){
for(Entry entry:listItems()){ for(Entry entry:listItems()){
if(entry!=null){ if(entry!=null){
@ -47,26 +69,41 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
public boolean isEmpty(){ public boolean isEmpty(){
return !iterator(true).hasNext(); return !iterator(true).hasNext();
} }
public void setEntry(short entryId, Entry entry){
setItem(0xffff & entryId, entry);
}
public Entry getOrCreate(short entryId){ public Entry getOrCreate(short entryId){
int id = 0xffff & entryId; int id = 0xffff & entryId;
Entry entry =get(id); Entry entry = getEntry(id);
if(entry !=null){ if(entry != null){
return entry; return entry;
} }
int count=id+1; boolean sparse = isSparse();
ensureSize(count); int count;
refreshCount(); if(sparse){
return get(id); count = childesCount() + 1;
}else {
count = id + 1;
} }
public Entry get(short entryId){ ensureSize(count);
int index = 0xffff & entryId; if(!sparse){
refreshCount();
return super.get(id);
}
SparseOffsetsArray offsetsArray = (SparseOffsetsArray) getOffsetArray();
offsetsArray.ensureArraySize(count);
int index = count - 1;
offsetsArray.setIdx(index, id);
refreshCount();
return super.get(index); return super.get(index);
} }
public Entry get(short entryId){
return getEntry(entryId);
}
public Entry getEntry(short entryId){ public Entry getEntry(short entryId){
return get(0xffff & entryId); return getEntry(0xffff & entryId);
}
public Entry getEntry(int entryId){
int index = getEntryIndex(entryId);
return super.get(index);
} }
@Override @Override
public Entry newInstance() { public Entry newInstance() {
@ -98,7 +135,7 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
JSONArray jsonArray=new JSONArray(); JSONArray jsonArray=new JSONArray();
int index=0; int index=0;
String name_id = Entry.NAME_id; String name_id = Entry.NAME_id;
for(Entry entry :listItems()){ for(Entry entry : listItems(true)){
JSONObject childObject = entry.toJson(); JSONObject childObject = entry.toJson();
if(childObject==null){ if(childObject==null){
continue; continue;
@ -112,33 +149,74 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
@Override @Override
public void fromJson(JSONArray json) { public void fromJson(JSONArray json) {
clearChildes(); clearChildes();
if(isSparse()){
fromJsonSparse(json);
}else {
fromJsonNonSparse(json);
}
refreshCountAndStart();
}
private void fromJsonNonSparse(JSONArray json){
int length=json.length(); int length=json.length();
ensureSize(length); ensureSize(length);
String name_id = Entry.NAME_id; String name_id = Entry.NAME_id;
for(int i=0;i<length;i++){ for(int i=0;i<length;i++){
JSONObject jsonObject= json.getJSONObject(i); JSONObject jsonObject = json.optJSONObject(i);
if(jsonObject==null){ if(jsonObject==null){
continue; continue;
} }
int id = jsonObject.getInt(name_id); int id = jsonObject.getInt(name_id);
ensureSize(id+1); ensureSize(id + 1);
Entry entry =get(id); Entry entry = super.get(id);
entry.fromJson(jsonObject); entry.fromJson(jsonObject);
} }
}
private void fromJsonSparse(JSONArray json){
SparseOffsetsArray offsetsArray = (SparseOffsetsArray) getOffsetArray();
offsetsArray.setSize(0);
int length = json.length();
ensureSize(length);
offsetsArray.setSize(length);
String name_id = Entry.NAME_id;
for(int i=0;i<length;i++){
JSONObject jsonObject = json.optJSONObject(i);
if(jsonObject==null){
offsetsArray.setIdx(i , OffsetArray.NO_ENTRY);
continue;
}
int id = jsonObject.getInt(name_id);
Entry entry = super.get(i);
offsetsArray.setIdx(i, id);
entry.fromJson(jsonObject);
}
}
public void merge(EntryArray entryArray){
if(entryArray ==null|| entryArray == this|| entryArray.isEmpty()){
return;
}
if(isSparse()){
mergeSparse(entryArray);
}else {
mergeNonSparse(entryArray);
}
refreshCountAndStart(); refreshCountAndStart();
} }
public void merge(EntryArray entryArray){ private void mergeSparse(EntryArray entryArray){
if(entryArray ==null|| entryArray ==this|| entryArray.isEmpty()){ Iterator<Entry> itr = entryArray.iterator(true);
return; while (itr.hasNext()){
Entry comingBlock = itr.next();
Entry existingBlock = getOrCreate((short) comingBlock.getId());
existingBlock.merge(comingBlock);
} }
}
private void mergeNonSparse(EntryArray entryArray){
ensureSize(entryArray.childesCount()); ensureSize(entryArray.childesCount());
Iterator<Entry> itr = entryArray.iterator(true); Iterator<Entry> itr = entryArray.iterator(true);
while (itr.hasNext()){ while (itr.hasNext()){
Entry comingBlock = itr.next(); Entry comingBlock = itr.next();
Entry existingBlock = get(comingBlock.getIndex()); Entry existingBlock = super.get(comingBlock.getIndex());
existingBlock.merge(comingBlock); existingBlock.merge(comingBlock);
} }
refreshCountAndStart();
} }
@Override @Override
public String toString(){ public String toString(){

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.array;
import com.reandroid.arsc.item.IntegerArray;
public class OffsetArray extends IntegerArray {
public OffsetArray(){
super();
}
public int getOffset(int i){
return super.getAt(i);
}
public void setOffset(int index, int value){
super.put(index, value);
}
public int[] getOffsets(){
int length = size();
int[] result = new int[length];
for(int i=0;i<length;i++){
result[i] = getOffset(i);
}
return result;
}
public static final int NO_ENTRY = 0xFFFFFFFF;
}

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -22,7 +22,6 @@ import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.io.BlockLoad; import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray; import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
@ -30,12 +29,12 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> implements BlockLoad { public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> implements BlockLoad {
private final IntegerArray mOffsets; private final OffsetArray mOffsets;
private final IntegerItem mItemStart; private final IntegerItem mItemStart;
private final IntegerItem mItemCount; private final IntegerItem mItemCount;
private final ByteArray mEnd4Block; private final ByteArray mEnd4Block;
private byte mEnd4Type; private byte mEnd4Type;
public OffsetBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){ public OffsetBlockArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super(); super();
this.mOffsets=offsets; this.mOffsets=offsets;
this.mItemCount=itemCount; this.mItemCount=itemCount;
@ -43,6 +42,9 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
this.mEnd4Block=new ByteArray(); this.mEnd4Block=new ByteArray();
mItemCount.setBlockLoad(this); mItemCount.setBlockLoad(this);
} }
OffsetArray getOffsetArray(){
return mOffsets;
}
void setEndBytes(byte b){ void setEndBytes(byte b){
this.mEnd4Type=b; this.mEnd4Type=b;
this.mEnd4Block.fill(b); this.mEnd4Block.fill(b);
@ -91,7 +93,8 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
@Override @Override
protected void onRefreshed() { protected void onRefreshed() {
int count=childesCount(); int count=childesCount();
mOffsets.setSize(count); OffsetArray offsetArray = this.mOffsets;
offsetArray.setSize(count);
T[] childes=getChildes(); T[] childes=getChildes();
int sum=0; int sum=0;
if(childes!=null){ if(childes!=null){
@ -105,7 +108,7 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
offset=sum; offset=sum;
sum+=item.countBytes(); sum+=item.countBytes();
} }
mOffsets.put(i, offset); offsetArray.setOffset(i, offset);
} }
} }
refreshCount(); refreshCount();
@ -167,7 +170,7 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
if(childes==null||childes.length==0){ if(childes==null||childes.length==0){
return; return;
} }
int[] offsetArray=mOffsets.toArray(); int[] offsetArray=mOffsets.getOffsets();
int max=childes.length; int max=childes.length;
int start=mItemStart.get(); int start=mItemStart.get();
reader.seek(start); reader.seek(start);

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -24,8 +24,8 @@ import com.reandroid.arsc.item.ResXmlString;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class ResXmlStringArray extends StringArray<ResXmlString> { public class ResXmlStringArray extends StringArray<ResXmlString> {
public ResXmlStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public ResXmlStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8); super(offsets, itemCount, itemStart, is_utf8);
} }
@Override @Override

View File

@ -0,0 +1,87 @@
/*
* 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;
public class SparseOffsetsArray extends OffsetArray{
public SparseOffsetsArray(){
super();
}
public int getHighestId(){
int result = NO_ENTRY;
int size = size();
for(int i=0; i<size;i++){
int id = getIdx(i);
if(id > result){
result = id;
}
}
if(result == NO_ENTRY){
result = 0;
}
return result;
}
public int indexOf(int idx){
int size = super.size();
for(int i=0; i<size; i++){
if(idx == getIdx(i)){
return i;
}
}
return NO_ENTRY;
}
public int getIdx(int i){
int value = super.getAt(i);
if(value != NO_ENTRY) {
value = value & 0xffff;
}
return value;
}
public void setIdx(int index, int idx){
int value;
if(idx == NO_ENTRY){
value = idx;
}else {
int offset = getAt(index) & 0xffff0000;
idx = idx & 0xffff;
value = offset | idx;
}
super.put(index, value);
}
@Override
public int getOffset(int i){
int value = super.getAt(i);
if(value == NO_ENTRY){
return value;
}
value = (value >>> 16) & 0xffff;
return value * 4;
}
@Override
public void setOffset(int index, int offset){
int value;
if(offset == NO_ENTRY){
value = 0;
}else {
int idx = getAt(0);
idx = idx & 0xffff;
offset = offset & 0xffff;
offset = offset / 4;
offset = offset << 16;
value = offset | idx;
}
super.put(index, value);
}
}

View File

@ -1,39 +0,0 @@
/*
* 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

@ -1,42 +0,0 @@
/*
* 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

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,12 +15,11 @@
*/ */
package com.reandroid.arsc.array; package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.SpecString; import com.reandroid.arsc.item.SpecString;
public class SpecStringArray extends StringArray<SpecString> { public class SpecStringArray extends StringArray<SpecString> {
public SpecStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public SpecStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8); super(offsets, itemCount, itemStart, is_utf8);
} }
@Override @Override

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -90,11 +90,11 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
return pair.getTypeBlockArray().getOrCreate(resConfig); return pair.getTypeBlockArray().getOrCreate(resConfig);
} }
public SpecTypePair getOrCreate(byte typeId){ public SpecTypePair getOrCreate(byte typeId){
SpecTypePair pair=getPair(typeId); SpecTypePair pair = getPair(typeId);
if(pair!=null){ if(pair!=null){
return pair; return pair;
} }
pair=createNext(); pair = createNext();
pair.setTypeId(typeId); pair.setTypeId(typeId);
return pair; return pair;
} }
@ -115,25 +115,9 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
} }
return null; return null;
} }
public byte getTypeId(){
SpecTypePair[] items=getChildes();
if(items==null){
return 0;
}
int max=items.length;
for(int i=0;i<max;i++){
SpecTypePair pair=items[i];
if(pair!=null){
return pair.getTypeId();
}
}
return 0;
}
@Override @Override
public SpecTypePair newInstance() { public SpecTypePair newInstance() {
SpecTypePair pair=new SpecTypePair(); return new SpecTypePair();
pair.setTypeId(getTypeId());
return pair;
} }
@Override @Override
public SpecTypePair[] newInstance(int len) { public SpecTypePair[] newInstance(int len) {
@ -147,7 +131,7 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
protected void onPreRefreshRefresh(){ protected void onPreRefreshRefresh(){
validateEntryCounts(); validateEntryCounts();
} }
// For android API < 26, it is required to have equal entry count on all SpecTypePair
private void validateEntryCounts(){ private void validateEntryCounts(){
Map<Byte, Integer> entryCountMap=mapHighestEntryCount(); Map<Byte, Integer> entryCountMap=mapHighestEntryCount();
for(Map.Entry<Byte, Integer> entry:entryCountMap.entrySet()){ for(Map.Entry<Byte, Integer> entry:entryCountMap.entrySet()){

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,7 +15,6 @@
*/ */
package com.reandroid.arsc.array; package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.StringItem; import com.reandroid.arsc.item.StringItem;
import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONConvert;
@ -29,7 +28,7 @@ import java.util.List;
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T> implements JSONConvert<JSONArray> { public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T> implements JSONConvert<JSONArray> {
private boolean mUtf8; private boolean mUtf8;
public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public StringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart); super(offsets, itemCount, itemStart);
this.mUtf8=is_utf8; this.mUtf8=is_utf8;
setEndBytes((byte)0x00); setEndBytes((byte)0x00);

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -17,7 +17,6 @@ package com.reandroid.arsc.array;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray; import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.StyleItem; import com.reandroid.arsc.item.StyleItem;
import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONConvert;
@ -26,7 +25,7 @@ import com.reandroid.json.JSONArray;
import java.io.IOException; import java.io.IOException;
public class StyleArray extends OffsetBlockArray<StyleItem> implements JSONConvert<JSONArray> { public class StyleArray extends OffsetBlockArray<StyleItem> implements JSONConvert<JSONArray> {
public StyleArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart) { public StyleArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart) {
super(offsets, itemCount, itemStart); super(offsets, itemCount, itemStart);
setEndBytes(END_BYTE); setEndBytes(END_BYTE);
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,12 +15,11 @@
*/ */
package com.reandroid.arsc.array; package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.TableString; import com.reandroid.arsc.item.TableString;
public class TableStringArray extends StringArray<TableString> { public class TableStringArray extends StringArray<TableString> {
public TableStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public TableStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8); super(offsets, itemCount, itemStart, is_utf8);
} }
@Override @Override

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -95,14 +95,17 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
return typeBlock.getEntry(entryId); return typeBlock.getEntry(entryId);
} }
public TypeBlock getOrCreate(ResConfig resConfig){ public TypeBlock getOrCreate(ResConfig resConfig){
TypeBlock typeBlock=getTypeBlock(resConfig); return getOrCreate(resConfig, false);
if(typeBlock!=null){ }
public TypeBlock getOrCreate(ResConfig resConfig, boolean sparse){
TypeBlock typeBlock = getTypeBlock(resConfig, sparse);
if(typeBlock != null){
return typeBlock; return typeBlock;
} }
byte id=getTypeId(); byte id = getTypeId();
typeBlock=createNext(); typeBlock = createNext(sparse);
typeBlock.setTypeId(id); typeBlock.setTypeId(id);
ResConfig config=typeBlock.getResConfig(); ResConfig config = typeBlock.getResConfig();
config.copyFrom(resConfig); config.copyFrom(resConfig);
return typeBlock; return typeBlock;
} }
@ -131,18 +134,24 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
return null; return null;
} }
public TypeBlock getTypeBlock(ResConfig config){ public TypeBlock getTypeBlock(ResConfig config){
return getTypeBlock(config, false);
}
public TypeBlock getTypeBlock(ResConfig config, boolean sparse){
if(config==null){ if(config==null){
return null; return null;
} }
TypeBlock[] items=getChildes(); TypeBlock[] items = getChildes();
if(items==null){ if(items == null){
return null; return null;
} }
int max=items.length; int length = items.length;
for(int i=0;i<max;i++){ for(int i = 0; i < length; i++){
TypeBlock block=items[i]; TypeBlock typeBlock = items[i];
if(config.equals(block.getResConfig())){ if(typeBlock == null || sparse != typeBlock.isSparse()){
return block; continue;
}
if(config.equals(typeBlock.getResConfig())){
return typeBlock;
} }
} }
return null; return null;
@ -204,12 +213,9 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
}; };
} }
private SpecBlock getSpecBlock(){ private SpecBlock getSpecBlock(){
Block parent=getParent(); SpecTypePair parent = getParent(SpecTypePair.class);
while(parent!=null){ if(parent != null){
if(parent instanceof SpecTypePair){ return parent.getSpecBlock();
return ((SpecTypePair) parent).getSpecBlock();
}
parent=parent.getParent();
} }
return null; return null;
} }
@ -223,8 +229,8 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
} }
@Override @Override
public TypeBlock newInstance() { public TypeBlock newInstance() {
byte id=getTypeId(); byte id = getTypeId();
TypeBlock typeBlock=new TypeBlock(); TypeBlock typeBlock = new TypeBlock(false);
typeBlock.setTypeId(id); typeBlock.setTypeId(id);
return typeBlock; return typeBlock;
} }
@ -232,6 +238,13 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
public TypeBlock[] newInstance(int len) { public TypeBlock[] newInstance(int len) {
return new TypeBlock[len]; return new TypeBlock[len];
} }
public TypeBlock createNext(boolean sparse){
byte id = getTypeId();
TypeBlock typeBlock = new TypeBlock(sparse);
typeBlock.setTypeId(id);
add(typeBlock);
return typeBlock;
}
@Override @Override
protected void onRefreshed() { protected void onRefreshed() {
@ -265,18 +278,20 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
public int getHighestEntryCount(){ public int getHighestEntryCount(){
int result=0; int result=0;
for(TypeBlock typeBlock:getChildes()){ for(TypeBlock typeBlock:getChildes()){
int count=typeBlock.getEntryArray().childesCount(); int high = typeBlock.getEntryArray().getHighestEntryId();
if(count>result){ if(high > result){
result=count; result = high;
} }
} }
return result; return result;
} }
public void setEntryCount(int count){ public void setEntryCount(int count){
for(TypeBlock typeBlock:getChildes()){ for(TypeBlock typeBlock:getChildes()){
if(!typeBlock.isSparse()){
typeBlock.setEntryCount(count); typeBlock.setEntryCount(count);
} }
} }
}
public TypeString getTypeString(){ public TypeString getTypeString(){
for(TypeBlock typeBlock:getChildes()){ for(TypeBlock typeBlock:getChildes()){
TypeString typeString=typeBlock.getTypeString(); TypeString typeString=typeBlock.getTypeString();
@ -305,21 +320,22 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
if(json == null){ if(json == null){
return; return;
} }
int length= json.length(); int length = json.length();
ensureSize(length); for(int i = 0; i < length; i++){
for (int i=0;i<length;i++){ JSONObject jsonObject = json.getJSONObject(i);
JSONObject jsonObject=json.getJSONObject(i); TypeBlock typeBlock = createNext(
TypeBlock typeBlock=get(i); jsonObject.optBoolean(TypeBlock.NAME_is_sparse, false));
typeBlock.fromJson(jsonObject); typeBlock.fromJson(jsonObject);
} }
} }
public void merge(TypeBlockArray typeBlockArray){ public void merge(TypeBlockArray typeBlockArray){
if(typeBlockArray==null||typeBlockArray==this){ if(typeBlockArray == null || typeBlockArray == this){
return; return;
} }
for(TypeBlock typeBlock:typeBlockArray.listItems()){ for(TypeBlock typeBlock:typeBlockArray.listItems()){
TypeBlock block=getOrCreate(typeBlock.getResConfig()); TypeBlock exist = getOrCreate(
block.merge(typeBlock); typeBlock.getResConfig(), typeBlock.isSparse());
exist.merge(typeBlock);
} }
} }
/** /**

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,13 +15,12 @@
*/ */
package com.reandroid.arsc.array; package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.TypeString; import com.reandroid.arsc.item.TypeString;
public class TypeStringArray extends StringArray<TypeString> { public class TypeStringArray extends StringArray<TypeString> {
private int lastCreateIndex; private int lastCreateIndex;
public TypeStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { public TypeStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8); super(offsets, itemCount, itemStart, is_utf8);
} }
@Override @Override

View File

@ -83,10 +83,13 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
return results; return results;
} }
public Collection<T> listItems(){ public Collection<T> listItems(){
return listItems(false);
}
public Collection<T> listItems(boolean skipNullBlocks){
return new AbstractCollection<T>() { return new AbstractCollection<T>() {
@Override @Override
public Iterator<T> iterator(){ public Iterator<T> iterator(){
return BlockArray.this.iterator(); return BlockArray.this.iterator(skipNullBlocks);
} }
@Override @Override
public boolean contains(Object o){ public boolean contains(Object o){
@ -277,12 +280,15 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
} }
int len=items.length; int len=items.length;
for(int i=0;i<len;i++){ for(int i=0;i<len;i++){
if(block==items[i]){ if(isEqual(items[i], block)){
return true; return true;
} }
} }
return false; return false;
} }
protected boolean isEqual(T item, Object obj){
return obj == item;
}
public void remove(Collection<T> blockList){ public void remove(Collection<T> blockList){
T[] items=elementData; T[] items=elementData;
if(items==null || items.length==0){ if(items==null || items.length==0){

View File

@ -1,42 +0,0 @@
/*
* 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

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,6 +16,8 @@
package com.reandroid.arsc.chunk; package com.reandroid.arsc.chunk;
import com.reandroid.arsc.array.EntryArray; import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.SparseOffsetsArray;
import com.reandroid.arsc.base.Block; import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.container.SpecTypePair; import com.reandroid.arsc.container.SpecTypePair;
import com.reandroid.arsc.header.TypeHeader; import com.reandroid.arsc.header.TypeHeader;
@ -39,11 +41,16 @@ public class TypeBlock extends Chunk<TypeHeader>
private final EntryArray mEntryArray; private final EntryArray mEntryArray;
private TypeString mTypeString; private TypeString mTypeString;
public TypeBlock() { public TypeBlock(boolean sparse) {
super(new TypeHeader(), 2); super(new TypeHeader(sparse), 2);
TypeHeader header = getHeaderBlock(); TypeHeader header = getHeaderBlock();
IntegerArray entryOffsets = new IntegerArray(); OffsetArray entryOffsets;
if(sparse){
entryOffsets = new SparseOffsetsArray();
}else {
entryOffsets = new OffsetArray();
}
this.mEntryArray = new EntryArray(entryOffsets, this.mEntryArray = new EntryArray(entryOffsets,
header.getCount(), header.getEntriesStart()); header.getCount(), header.getEntriesStart());
@ -52,6 +59,9 @@ public class TypeBlock extends Chunk<TypeHeader>
addChild(entryOffsets); addChild(entryOffsets);
addChild(mEntryArray); addChild(mEntryArray);
} }
public boolean isSparse(){
return getHeaderBlock().isSparse();
}
public void destroy(){ public void destroy(){
getEntryArray().destroy(); getEntryArray().destroy();
setId(0); setId(0);
@ -242,7 +252,10 @@ public class TypeBlock extends Chunk<TypeHeader>
} }
@Override @Override
public JSONObject toJson() { public JSONObject toJson() {
JSONObject jsonObject=new JSONObject(); JSONObject jsonObject = new JSONObject();
if(isSparse()){
jsonObject.put(NAME_is_sparse, true);
}
jsonObject.put(NAME_id, getId()); jsonObject.put(NAME_id, getId());
jsonObject.put(NAME_name, getTypeName()); jsonObject.put(NAME_name, getTypeName());
jsonObject.put(NAME_config, getResConfig().toJson()); jsonObject.put(NAME_config, getResConfig().toJson());
@ -274,12 +287,16 @@ public class TypeBlock extends Chunk<TypeHeader>
} }
@Override @Override
public int compareTo(TypeBlock typeBlock) { public int compareTo(TypeBlock typeBlock) {
int id1= getId(); int id1 = getId();
int id2=typeBlock.getId(); int id2 = typeBlock.getId();
if(id1!=id2){ if(id1 != id2){
return Integer.compare(id1, id2); return Integer.compare(id1, id2);
} }
return getResConfig().compareTo(typeBlock.getResConfig()); String q1 = (isSparse() ? "1" : "0")
+ getResConfig().getQualifiers();
String q2 = (typeBlock.isSparse() ? "1" : "0")
+ typeBlock.getResConfig().getQualifiers();
return q1.compareTo(q2);
} }
/** /**
* It is allowed to have duplicate entry name therefore it is not recommend to use this. * It is allowed to have duplicate entry name therefore it is not recommend to use this.
@ -311,4 +328,5 @@ public class TypeBlock extends Chunk<TypeHeader>
public static final String NAME_config = "config"; public static final String NAME_config = "config";
public static final String NAME_id = "id"; public static final String NAME_id = "id";
public static final String NAME_entries = "entries"; public static final String NAME_entries = "entries";
public static final String NAME_is_sparse = "is_sparse";
} }

View File

@ -117,13 +117,10 @@ public class PackageBody extends FixedBlockContainer {
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()){ if(typeHeader.isSparse()){
SparseTypeBlock sparseTypeBlock = specTypePair String junk = "";
.getSparseTypeBlockArray().createNext();
sparseTypeBlock.readBytes(reader);
}else {
TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext();
typeBlock.readBytes(reader);
} }
TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext(typeHeader.isSparse());
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();

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,7 +16,6 @@
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.array.SparseTypeBlockArray;
import com.reandroid.arsc.chunk.*; 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;
@ -39,31 +38,23 @@ 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.sparseTypeBlockArray = new SparseTypeBlockArray();
this.mChildes=new Block[]{specBlock, typeBlockArray, sparseTypeBlockArray}; this.mChildes = new Block[]{specBlock, typeBlockArray};
mSpecBlock.setIndex(0);
mTypeBlockArray.setIndex(1); specBlock.setIndex(0);
sparseTypeBlockArray.setIndex(2); typeBlockArray.setIndex(1);
mSpecBlock.setParent(this);
mTypeBlockArray.setParent(this); specBlock.setParent(this);
sparseTypeBlockArray.setParent(this); typeBlockArray.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()){
@ -233,12 +224,8 @@ public class SpecTypePair extends BlockContainer<Block>
} }
private void readTypeBlock(BlockReader reader) throws IOException { private void readTypeBlock(BlockReader reader) throws IOException {
TypeHeader typeHeader = reader.readTypeHeader(); TypeHeader typeHeader = reader.readTypeHeader();
if(typeHeader.isSparse()){ TypeBlock typeBlock = mTypeBlockArray.createNext(typeHeader.isSparse());
SparseTypeBlock sparseTypeBlock = sparseTypeBlockArray.createNext(); typeBlock.readBytes(reader);
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);
@ -281,7 +268,6 @@ 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) {
@ -304,4 +290,5 @@ public class SpecTypePair extends BlockContainer<Block>
} }
public static final String NAME_types = "types"; public static final String NAME_types = "types";
public static final String NAME_sparse_types = "sparse_types";
} }

View File

@ -27,7 +27,7 @@ public class TypeHeader extends HeaderBlock{
private final IntegerItem count; private final IntegerItem count;
private final IntegerItem entriesStart; private final IntegerItem entriesStart;
private final ResConfig config; private final ResConfig config;
public TypeHeader() { public TypeHeader(boolean sparse) {
super(ChunkType.TYPE.ID); super(ChunkType.TYPE.ID);
this.id = new ByteItem(); this.id = new ByteItem();
this.flags = new ByteItem(); this.flags = new ByteItem();
@ -42,6 +42,7 @@ public class TypeHeader extends HeaderBlock{
addChild(count); addChild(count);
addChild(entriesStart); addChild(entriesStart);
addChild(config); addChild(config);
setSparse(sparse);
} }
public boolean isSparse(){ public boolean isSparse(){
return (getFlags().get() & FLAG_SPARSE) == FLAG_SPARSE; return (getFlags().get() & FLAG_SPARSE) == FLAG_SPARSE;

View File

@ -69,7 +69,7 @@ import java.io.*;
return specHeader; return specHeader;
} }
public TypeHeader readTypeHeader() throws IOException{ public TypeHeader readTypeHeader() throws IOException{
TypeHeader typeHeader = new TypeHeader(); TypeHeader typeHeader = new TypeHeader(false);
if(available() < typeHeader.getMinimumSize()){ if(available() < typeHeader.getMinimumSize()){
return null; return null;
} }

View File

@ -113,6 +113,14 @@ public class IntegerArray extends BlockItem {
(bts[i+2] & 0xff) << 16 | (bts[i+2] & 0xff) << 16 |
(bts[i+3] & 0xff) << 24; (bts[i+3] & 0xff) << 24;
} }
public int getAt(int index){
int i=index*4;
byte[] bts = getBytesInternal();
return bts[i] & 0xff |
(bts[i+1] & 0xff) << 8 |
(bts[i+2] & 0xff) << 16 |
(bts[i+3] & 0xff) << 24;
}
public final int size(){ public final int size(){
return getBytesLength()/4; return getBytesLength()/4;
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,10 +15,7 @@
*/ */
package com.reandroid.arsc.pool; package com.reandroid.arsc.pool;
import com.reandroid.arsc.array.ResXmlIDArray; import com.reandroid.arsc.array.*;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.ResXmlStringArray;
import com.reandroid.arsc.array.StyleArray;
import com.reandroid.arsc.chunk.xml.ResXmlDocument; import com.reandroid.arsc.chunk.xml.ResXmlDocument;
import com.reandroid.arsc.chunk.xml.ResXmlIDMap; import com.reandroid.arsc.chunk.xml.ResXmlIDMap;
import com.reandroid.arsc.group.StringGroup; import com.reandroid.arsc.group.StringGroup;
@ -26,7 +23,7 @@ import com.reandroid.arsc.item.*;
import java.util.Objects; import java.util.Objects;
public class ResXmlStringPool extends StringPool<ResXmlString> { public class ResXmlStringPool extends StringPool<ResXmlString> {
public ResXmlStringPool(boolean is_utf8) { public ResXmlStringPool(boolean is_utf8) {
super(is_utf8); super(is_utf8);
} }
@ -55,7 +52,7 @@ import java.util.Objects;
} }
} }
@Override @Override
StringArray<ResXmlString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { StringArray<ResXmlString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new ResXmlStringArray(offsets, itemCount, itemStart, is_utf8); return new ResXmlStringArray(offsets, itemCount, itemStart, is_utf8);
} }
public ResXmlString getOrCreate(String str){ public ResXmlString getOrCreate(String str){

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,11 +15,10 @@
*/ */
package com.reandroid.arsc.pool; package com.reandroid.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.SpecStringArray; import com.reandroid.arsc.array.SpecStringArray;
import com.reandroid.arsc.array.StringArray; import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.SpecString; import com.reandroid.arsc.item.SpecString;
@ -29,7 +28,7 @@ public class SpecStringPool extends StringPool<SpecString> {
} }
@Override @Override
StringArray<SpecString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { StringArray<SpecString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new SpecStringArray(offsets, itemCount, itemStart, is_utf8); return new SpecStringArray(offsets, itemCount, itemStart, is_utf8);
} }
public PackageBlock getPackageBlock(){ public PackageBlock getPackageBlock(){

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,23 +15,24 @@
*/ */
package com.reandroid.arsc.pool; package com.reandroid.arsc.pool;
import com.reandroid.arsc.array.StringArray; import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StyleArray; import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.base.Block; import com.reandroid.arsc.array.StyleArray;
import com.reandroid.arsc.chunk.Chunk; import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.group.StringGroup; import com.reandroid.arsc.chunk.Chunk;
import com.reandroid.arsc.header.StringPoolHeader; import com.reandroid.arsc.group.StringGroup;
import com.reandroid.arsc.io.BlockLoad; import com.reandroid.arsc.header.StringPoolHeader;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.item.*; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.json.JSONArray; import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONArray;
import com.reandroid.json.JSONConvert;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> { public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
private final StringArray<T> mArrayStrings; private final StringArray<T> mArrayStrings;
private final StyleArray mArrayStyles; private final StyleArray mArrayStyles;
@ -40,8 +41,8 @@ package com.reandroid.arsc.pool;
StringPool(boolean is_utf8){ StringPool(boolean is_utf8){
super(new StringPoolHeader(), 4); super(new StringPoolHeader(), 4);
IntegerArray offsetStrings = new IntegerArray(); OffsetArray offsetStrings = new OffsetArray();
IntegerArray offsetStyles = new IntegerArray(); OffsetArray offsetStyles = new OffsetArray();
StringPoolHeader header = getHeaderBlock(); StringPoolHeader header = getHeaderBlock();
@ -278,7 +279,7 @@ package com.reandroid.arsc.pool;
getHeaderBlock().setSorted(sorted); getHeaderBlock().setSorted(sorted);
} }
abstract StringArray<T> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8); abstract StringArray<T> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8);
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {
mArrayStrings.refreshCountAndStart(); mArrayStrings.refreshCountAndStart();

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,6 +15,7 @@
*/ */
package com.reandroid.arsc.pool; package com.reandroid.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StringArray; import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.TableStringArray; import com.reandroid.arsc.array.TableStringArray;
import com.reandroid.arsc.chunk.ChunkType; import com.reandroid.arsc.chunk.ChunkType;
@ -29,13 +30,13 @@ import com.reandroid.arsc.item.TableString;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
public class TableStringPool extends StringPool<TableString> { public class TableStringPool extends StringPool<TableString> {
public TableStringPool(boolean is_utf8) { public TableStringPool(boolean is_utf8) {
super(is_utf8); super(is_utf8);
} }
@Override @Override
StringArray<TableString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { StringArray<TableString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new TableStringArray(offsets, itemCount, itemStart, is_utf8); return new TableStringArray(offsets, itemCount, itemStart, is_utf8);
} }
public void merge(TableStringPool stringPool){ public void merge(TableStringPool stringPool){

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -15,6 +15,7 @@
*/ */
package com.reandroid.arsc.pool; package com.reandroid.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StringArray; import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.TypeStringArray; import com.reandroid.arsc.array.TypeStringArray;
import com.reandroid.arsc.chunk.TypeBlock; import com.reandroid.arsc.chunk.TypeBlock;
@ -80,7 +81,7 @@ public class TypeStringPool extends StringPool<TypeString> {
return group.get(0); return group.get(0);
} }
@Override @Override
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { StringArray<TypeString> newInstance(OffsetArray 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,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -13,27 +13,28 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.arsc.value; package com.reandroid.arsc.value;
import com.reandroid.arsc.array.ResValueMapArray; import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.base.Block; import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.base.BlockCounter; import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.chunk.SpecBlock; import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.SpecBlock;
import com.reandroid.arsc.chunk.TypeBlock; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.container.SpecTypePair; import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.group.EntryGroup; import com.reandroid.arsc.container.SpecTypePair;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.group.EntryGroup;
import com.reandroid.arsc.item.*; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.json.JSONConvert; import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONObject; import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class Entry extends Block implements JSONConvert<JSONObject> { public class Entry extends Block implements JSONConvert<JSONObject> {
private TableEntry<?, ?> mTableEntry; private TableEntry<?, ?> mTableEntry;
public Entry(){ public Entry(){
@ -65,7 +66,12 @@
ensureTableEntry(isComplex); ensureTableEntry(isComplex);
} }
public int getId(){ public int getId(){
return getIndex(); int id = getIndex();
EntryArray entryArray = getParentInstance(EntryArray.class);
if(entryArray != null){
id = entryArray.getEntryId(id);
}
return id;
} }
public String getName(){ public String getName(){
SpecString specString = getSpecString(); SpecString specString = getSpecString();
@ -456,4 +462,4 @@
} }
public static final String NAME_id = "id"; public static final String NAME_id = "id";
} }

View File

@ -1,40 +0,0 @@
/*
* 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();
}
}