mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-02 07:04:27 +02:00
performance: link pool strings when only needed #36
This commit is contained in:
parent
c80e0943d3
commit
b6bbac2dcf
@ -16,6 +16,8 @@
|
||||
package com.reandroid.arsc.array;
|
||||
|
||||
import com.reandroid.arsc.item.IntegerItem;
|
||||
import com.reandroid.arsc.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONArray;
|
||||
@ -28,6 +30,20 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
|
||||
public EntryArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){
|
||||
super(offsets, itemCount, itemStart);
|
||||
}
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
Iterator<Entry> itr = iterator(true);
|
||||
while (itr.hasNext()){
|
||||
Entry entry = itr.next();
|
||||
entry.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
}
|
||||
public void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
Iterator<Entry> itr = iterator(true);
|
||||
while (itr.hasNext()){
|
||||
Entry entry = itr.next();
|
||||
entry.linkSpecStringsInternal(specStringPool);
|
||||
}
|
||||
}
|
||||
public int getHighestEntryId(){
|
||||
if(isSparse()){
|
||||
return ((SparseOffsetsArray) getOffsetArray()).getHighestId();
|
||||
|
@ -27,6 +27,7 @@ import com.reandroid.arsc.header.PackageHeader;
|
||||
import com.reandroid.arsc.list.OverlayableList;
|
||||
import com.reandroid.arsc.list.StagedAliasList;
|
||||
import com.reandroid.arsc.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.arsc.pool.TypeStringPool;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.LibraryInfo;
|
||||
@ -68,6 +69,16 @@ public class PackageBlock extends Chunk<PackageHeader>
|
||||
addChild(mSpecStringPool);
|
||||
addChild(mBody);
|
||||
}
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(SpecTypePair specTypePair : listAllSpecTypePair()){
|
||||
specTypePair.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
}
|
||||
public void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
for(SpecTypePair specTypePair : listAllSpecTypePair()){
|
||||
specTypePair.linkSpecStringsInternal(specStringPool);
|
||||
}
|
||||
}
|
||||
public void destroy(){
|
||||
getEntriesGroupMap().clear();
|
||||
getPackageBody().destroy();
|
||||
@ -221,6 +232,7 @@ public class PackageBlock extends Chunk<PackageHeader>
|
||||
if(!this.entryGroupMapLocked){
|
||||
return;
|
||||
}
|
||||
entryGroupMapLocked = false;
|
||||
Map<Integer, EntryGroup> map = this.mEntriesGroup;
|
||||
map.clear();
|
||||
createEntryGroupMap(map);
|
||||
|
@ -53,6 +53,11 @@ public class TableBlock extends Chunk<TableHeader>
|
||||
addChild(mPackageArray);
|
||||
}
|
||||
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(PackageBlock packageBlock : listPackages()){
|
||||
packageBlock.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
}
|
||||
public List<Entry> resolveReference(int referenceId){
|
||||
return resolveReference(referenceId, null);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import com.reandroid.arsc.header.TypeHeader;
|
||||
import com.reandroid.arsc.io.BlockLoad;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
import com.reandroid.arsc.item.*;
|
||||
import com.reandroid.arsc.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.arsc.pool.TypeStringPool;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResConfig;
|
||||
@ -59,6 +61,14 @@ public class TypeBlock extends Chunk<TypeHeader>
|
||||
addChild(entryOffsets);
|
||||
addChild(mEntryArray);
|
||||
}
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
EntryArray entryArray = getEntryArray();
|
||||
entryArray.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
public void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
EntryArray entryArray = getEntryArray();
|
||||
entryArray.linkSpecStringsInternal(specStringPool);
|
||||
}
|
||||
public boolean isSparse(){
|
||||
return getHeaderBlock().isSparse();
|
||||
}
|
||||
|
@ -232,6 +232,7 @@
|
||||
@Override
|
||||
public void onReadBytes(BlockReader reader) throws IOException {
|
||||
super.onReadBytes(reader);
|
||||
super.onDataLoaded();
|
||||
linkAll();
|
||||
linkStartNameSpace();
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ 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.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResConfig;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
@ -55,6 +57,16 @@ public class SpecTypePair extends BlockContainer<Block>
|
||||
this(new SpecBlock(), new TypeBlockArray());
|
||||
}
|
||||
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(TypeBlock typeBlock:listTypeBlocks()){
|
||||
typeBlock.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
}
|
||||
public void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
for(TypeBlock typeBlock:listTypeBlocks()){
|
||||
typeBlock.linkSpecStringsInternal(specStringPool);
|
||||
}
|
||||
}
|
||||
public Map<Integer, EntryGroup> createEntryGroups(){
|
||||
Map<Integer, EntryGroup> map = new HashMap<>();
|
||||
for(TypeBlock typeBlock:listTypeBlocks()){
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.reandroid.arsc.item;
|
||||
|
||||
|
||||
public class ResXmlString extends StringItem {
|
||||
public ResXmlString(boolean utf8) {
|
||||
super(utf8);
|
||||
@ -24,4 +23,7 @@ public class ResXmlString extends StringItem {
|
||||
this(utf8);
|
||||
set(value);
|
||||
}
|
||||
@Override
|
||||
void ensureStringLinkUnlocked(){
|
||||
}
|
||||
}
|
||||
|
@ -49,11 +49,19 @@ public class StringItem extends BlockItem implements JSONConvert<JSONObject> {
|
||||
mReferencedList.clear();
|
||||
}
|
||||
public boolean hasReference(){
|
||||
ensureStringLinkUnlocked();
|
||||
return mReferencedList.size()>0;
|
||||
}
|
||||
public Collection<ReferenceItem> getReferencedList(){
|
||||
ensureStringLinkUnlocked();
|
||||
return mReferencedList;
|
||||
}
|
||||
void ensureStringLinkUnlocked(){
|
||||
StringPool<?> stringPool = getParentInstance(StringPool.class);
|
||||
if(stringPool != null){
|
||||
stringPool.ensureStringLinkUnlockedInternal();
|
||||
}
|
||||
}
|
||||
public void addReference(ReferenceItem ref){
|
||||
if(ref!=null){
|
||||
mReferencedList.add(ref);
|
||||
@ -269,7 +277,7 @@ public class StringItem extends BlockItem implements JSONConvert<JSONObject> {
|
||||
if(str == null){
|
||||
return "NULL";
|
||||
}
|
||||
return "USED BY="+getReferencedList().size()+"{"+str+"}";
|
||||
return "USED BY=" + mReferencedList.size() + "{" + str + "}";
|
||||
}
|
||||
|
||||
private static int[] decodeUtf8StringByteLength(byte[] lengthBytes) {
|
||||
|
@ -36,6 +36,9 @@ package com.reandroid.arsc.item;
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
void ensureStringLinkUnlocked(){
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("0x%02x", getId())+':'+get();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import java.util.Objects;
|
||||
|
||||
public class ResXmlStringPool extends StringPool<ResXmlString> {
|
||||
public ResXmlStringPool(boolean is_utf8) {
|
||||
super(is_utf8);
|
||||
super(is_utf8, false);
|
||||
}
|
||||
@Override
|
||||
public ResXmlString removeReference(ReferenceItem referenceItem){
|
||||
|
@ -34,4 +34,12 @@ public class SpecStringPool extends StringPool<SpecString> {
|
||||
public PackageBlock getPackageBlock(){
|
||||
return getParent(PackageBlock.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
void linkStrings(){
|
||||
PackageBlock packageBlock = getPackageBlock();
|
||||
if(packageBlock != null){
|
||||
packageBlock.linkSpecStringsInternal(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,14 @@ import java.util.*;
|
||||
|
||||
|
||||
public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
|
||||
private final Object mLock = new Object();
|
||||
private final StringArray<T> mArrayStrings;
|
||||
private final StyleArray mArrayStyles;
|
||||
|
||||
private final Map<String, StringGroup<T>> mUniqueMap;
|
||||
private boolean stringLinkLocked;
|
||||
|
||||
StringPool(boolean is_utf8){
|
||||
StringPool(boolean is_utf8, boolean stringLinkLocked){
|
||||
super(new StringPoolHeader(), 4);
|
||||
|
||||
OffsetArray offsetStrings = new OffsetArray();
|
||||
@ -68,7 +70,30 @@ public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolH
|
||||
header.getFlagUtf8().setBlockLoad(this);
|
||||
|
||||
mUniqueMap = new HashMap<>();
|
||||
this.stringLinkLocked = stringLinkLocked;
|
||||
}
|
||||
StringPool(boolean is_utf8){
|
||||
this(is_utf8, true);
|
||||
}
|
||||
|
||||
public boolean isStringLinkLocked(){
|
||||
return stringLinkLocked;
|
||||
}
|
||||
public void ensureStringLinkUnlockedInternal(){
|
||||
if(!stringLinkLocked){
|
||||
return;
|
||||
}
|
||||
synchronized (mLock){
|
||||
if(!stringLinkLocked){
|
||||
return;
|
||||
}
|
||||
stringLinkLocked = false;
|
||||
linkStrings();
|
||||
}
|
||||
}
|
||||
void linkStrings(){
|
||||
}
|
||||
|
||||
public void removeString(T item){
|
||||
getStringsArray().remove(item);
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ import com.reandroid.arsc.array.OffsetArray;
|
||||
import com.reandroid.arsc.array.StringArray;
|
||||
import com.reandroid.arsc.array.TableStringArray;
|
||||
import com.reandroid.arsc.chunk.ChunkType;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
import com.reandroid.arsc.chunk.UnknownChunk;
|
||||
import com.reandroid.arsc.header.HeaderBlock;
|
||||
import com.reandroid.arsc.header.TableHeader;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
import com.reandroid.arsc.item.IntegerArray;
|
||||
import com.reandroid.arsc.item.IntegerItem;
|
||||
import com.reandroid.arsc.item.TableString;
|
||||
|
||||
@ -35,6 +35,13 @@ public class TableStringPool extends StringPool<TableString> {
|
||||
super(is_utf8);
|
||||
}
|
||||
|
||||
@Override
|
||||
void linkStrings(){
|
||||
TableBlock tableBlock = getParentInstance(TableBlock.class);
|
||||
if(tableBlock != null){
|
||||
tableBlock.linkTableStringsInternal(this);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
StringArray<TableString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||
return new TableStringArray(offsets, itemCount, itemStart, is_utf8);
|
||||
|
@ -27,7 +27,7 @@ import com.reandroid.arsc.item.TypeString;
|
||||
public class TypeStringPool extends StringPool<TypeString> {
|
||||
private final IntegerItem mTypeIdOffset;
|
||||
public TypeStringPool(boolean is_utf8, IntegerItem typeIdOffset) {
|
||||
super(is_utf8);
|
||||
super(is_utf8, false);
|
||||
this.mTypeIdOffset = typeIdOffset;
|
||||
}
|
||||
public int idOf(String typeName){
|
||||
|
@ -27,6 +27,8 @@ import com.reandroid.arsc.container.SpecTypePair;
|
||||
import com.reandroid.arsc.group.EntryGroup;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
import com.reandroid.arsc.item.*;
|
||||
import com.reandroid.arsc.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
@ -41,6 +43,15 @@ public class Entry extends Block implements JSONConvert<JSONObject> {
|
||||
super();
|
||||
}
|
||||
|
||||
public void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
TableEntry<?, ?> tableEntry = getTableEntry();
|
||||
tableEntry.linkTableStringsInternal(tableStringPool);
|
||||
}
|
||||
public void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
TableEntry<?, ?> tableEntry = getTableEntry();
|
||||
ValueHeader header = tableEntry.getHeader();
|
||||
header.linkSpecStringsInternal(specStringPool);
|
||||
}
|
||||
public ResValue getResValue(){
|
||||
TableEntry<?, ?> tableEntry = getTableEntry();
|
||||
if(tableEntry instanceof ResTableEntry){
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
public class ResTableEntry extends TableEntry<EntryHeader, ResValue> {
|
||||
@ -22,6 +23,10 @@ public class ResTableEntry extends TableEntry<EntryHeader, ResValue> {
|
||||
super(new EntryHeader(), new ResValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
getValue().linkTableStrings(tableStringPool);
|
||||
}
|
||||
@Override
|
||||
void onRemoved(){
|
||||
getHeader().onRemoved();
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
import com.reandroid.arsc.array.ResValueMapArray;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
public class ResTableMapEntry extends TableEntry<EntryHeaderMap, ResValueMapArray> {
|
||||
@ -42,6 +43,12 @@ public class ResTableMapEntry extends TableEntry<EntryHeaderMap, ResValueMapArra
|
||||
getValue().setChildesCount(valuesCount);
|
||||
}
|
||||
@Override
|
||||
void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(ResValueMap resValueMap : listResValueMap()){
|
||||
resValueMap.linkTableStrings(tableStringPool);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void onHeaderLoaded(ValueHeader valueHeader){
|
||||
getValue().setChildesCount(getValuesCount());
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package com.reandroid.arsc.value;
|
||||
import com.reandroid.arsc.base.Block;
|
||||
import com.reandroid.arsc.base.BlockCounter;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
@ -96,6 +97,7 @@ public abstract class TableEntry<HEADER extends ValueHeader, VALUE extends Block
|
||||
}
|
||||
abstract void onRemoved();
|
||||
abstract boolean shouldMerge(TableEntry<?, ?> tableEntry);
|
||||
abstract void linkTableStringsInternal(TableStringPool tableStringPool);
|
||||
|
||||
public abstract void merge(TableEntry<?, ?> tableEntry);
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ import com.reandroid.arsc.base.Block;
|
||||
import com.reandroid.arsc.chunk.ParentChunk;
|
||||
import com.reandroid.arsc.io.BlockReader;
|
||||
import com.reandroid.arsc.item.*;
|
||||
import com.reandroid.arsc.pool.SpecStringPool;
|
||||
import com.reandroid.arsc.pool.StringPool;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
@ -32,6 +33,21 @@ public class ValueHeader extends BlockItem implements JSONConvert<JSONObject> {
|
||||
writeSize();
|
||||
putInteger(getBytesInternal(), OFFSET_SPEC_REFERENCE, -1);
|
||||
}
|
||||
|
||||
void linkSpecStringsInternal(SpecStringPool specStringPool){
|
||||
int key = getKey();
|
||||
SpecString specString = specStringPool.get(key);
|
||||
if(specString == null){
|
||||
mStringReference = null;
|
||||
return;
|
||||
}
|
||||
if(mStringReference != null){
|
||||
specString.removeReference(mStringReference);
|
||||
}
|
||||
ReferenceItem stringReference = new ReferenceBlock<>(this, OFFSET_SPEC_REFERENCE);
|
||||
mStringReference = stringReference;
|
||||
specString.addReference(stringReference);
|
||||
}
|
||||
public void onRemoved(){
|
||||
unLinkStringReference();
|
||||
}
|
||||
@ -116,7 +132,11 @@ public class ValueHeader extends BlockItem implements JSONConvert<JSONObject> {
|
||||
}
|
||||
|
||||
private void linkStringReference(){
|
||||
linkStringReference(getNameString());
|
||||
StringPool<?> specStringPool = getSpecStringPool();
|
||||
if(specStringPool == null || specStringPool.isStringLinkLocked()){
|
||||
return;
|
||||
}
|
||||
linkStringReference(specStringPool.get(getKey()));
|
||||
}
|
||||
private void linkStringReference(StringItem stringItem){
|
||||
unLinkStringReference();
|
||||
@ -167,7 +187,6 @@ public class ValueHeader extends BlockItem implements JSONConvert<JSONObject> {
|
||||
int size = reader.readUnsignedShort();
|
||||
setBytesLength(size, false);
|
||||
reader.readFully(getBytesInternal());
|
||||
linkStringReference();
|
||||
}
|
||||
private void setName(String name){
|
||||
if(name==null){
|
||||
|
@ -23,6 +23,7 @@ import com.reandroid.arsc.item.ReferenceBlock;
|
||||
import com.reandroid.arsc.item.ReferenceItem;
|
||||
import com.reandroid.arsc.item.StringItem;
|
||||
import com.reandroid.arsc.pool.StringPool;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
@ -39,6 +40,10 @@ import java.util.Objects;
|
||||
|
||||
writeSize();
|
||||
}
|
||||
|
||||
void linkTableStrings(TableStringPool tableStringPool){
|
||||
linkStringReference(tableStringPool);
|
||||
}
|
||||
public void onRemoved(){
|
||||
unLinkStringReference();
|
||||
}
|
||||
@ -78,7 +83,7 @@ import java.util.Objects;
|
||||
int size = countBytes() - offset;
|
||||
putShort(getBytesInternal(), offset + OFFSET_SIZE, (short) size);
|
||||
}
|
||||
private void onDataLoaded(){
|
||||
protected void onDataLoaded(){
|
||||
if(getValueType() == ValueType.STRING){
|
||||
linkStringReference();
|
||||
}else {
|
||||
@ -136,8 +141,16 @@ import java.util.Objects;
|
||||
}
|
||||
}
|
||||
private void linkStringReference(){
|
||||
StringItem tableString = getDataAsPoolString();
|
||||
StringPool<?> stringPool = getStringPool();
|
||||
if(stringPool == null || stringPool.isStringLinkLocked()){
|
||||
return;
|
||||
}
|
||||
linkStringReference(stringPool);
|
||||
}
|
||||
private void linkStringReference(StringPool<?> stringPool){
|
||||
StringItem tableString = stringPool.get(getData());
|
||||
if(tableString == null){
|
||||
unLinkStringReference();
|
||||
return;
|
||||
}
|
||||
ReferenceItem stringReference = mStringReference;
|
||||
@ -181,7 +194,6 @@ import java.util.Objects;
|
||||
setBytesLength(this.sizeOffset + 8, false);
|
||||
writeSize();
|
||||
}
|
||||
onDataLoaded();
|
||||
}
|
||||
private int initializeBytes(BlockReader reader) throws IOException {
|
||||
int position = reader.getPosition();
|
||||
|
Loading…
x
Reference in New Issue
Block a user