mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 14:44:27 +02:00
[XML] clean unused strings and res id from pool
This commit is contained in:
parent
9914722bac
commit
dfe85947b4
@ -15,15 +15,45 @@
|
||||
*/
|
||||
package com.reandroid.arsc.array;
|
||||
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlIDMap;
|
||||
import com.reandroid.arsc.item.IntegerArray;
|
||||
import com.reandroid.arsc.item.IntegerItem;
|
||||
import com.reandroid.arsc.item.ResXmlString;
|
||||
|
||||
public class ResXmlStringArray extends StringArray<ResXmlString> {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ResXmlStringArray extends StringArray<ResXmlString> {
|
||||
public ResXmlStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||
super(offsets, itemCount, itemStart, is_utf8);
|
||||
}
|
||||
@Override
|
||||
List<ResXmlString> listUnusedStringsToRemove(){
|
||||
List<ResXmlString> results=new ArrayList<>();
|
||||
ResXmlIDMap idMap = getResXmlIDMap();
|
||||
int lastIndex = -1;
|
||||
if(idMap!=null){
|
||||
lastIndex = idMap.countId();
|
||||
}
|
||||
for(ResXmlString item:listItems()){
|
||||
if(item == null
|
||||
|| item.hasReference()
|
||||
|| item.getIndex()<lastIndex){
|
||||
continue;
|
||||
}
|
||||
results.add(item);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
private ResXmlIDMap getResXmlIDMap(){
|
||||
ResXmlDocument xmlDocument = getParentInstance(ResXmlDocument.class);
|
||||
if(xmlDocument!=null){
|
||||
return xmlDocument.getResXmlIDMap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public ResXmlString newInstance() {
|
||||
return new ResXmlString(isUtf8());
|
||||
}
|
||||
|
@ -51,13 +51,16 @@ public abstract class StringArray<T extends StringItem> extends OffsetBlockArray
|
||||
};
|
||||
}
|
||||
public List<T> removeUnusedStrings(){
|
||||
List<T> unusedList=listUnusedStrings();
|
||||
List<T> unusedList = listUnusedStringsToRemove();
|
||||
remove(unusedList);
|
||||
for(T item:unusedList){
|
||||
item.onRemoved();
|
||||
}
|
||||
return unusedList;
|
||||
}
|
||||
List<T> listUnusedStringsToRemove(){
|
||||
return listUnusedStrings();
|
||||
}
|
||||
public List<T> listUnusedStrings(){
|
||||
List<T> results=new ArrayList<>();
|
||||
for(T item:listItems()){
|
||||
|
@ -221,7 +221,7 @@ import java.util.*;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public Set<TableBlock> getFrameWorks(){
|
||||
public List<TableBlock> getFrameWorks(){
|
||||
return mFrameWorks;
|
||||
}
|
||||
public void addFramework(TableBlock tableBlock){
|
||||
@ -229,12 +229,18 @@ import java.util.*;
|
||||
return;
|
||||
}
|
||||
for(TableBlock frm:tableBlock.getFrameWorks()){
|
||||
if(frm==this){
|
||||
if(frm==this || frm==tableBlock || tableBlock.equals(frm)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
mFrameWorks.add(tableBlock);
|
||||
}
|
||||
public void removeFramework(TableBlock tableBlock){
|
||||
mFrameWorks.remove(tableBlock);
|
||||
}
|
||||
public void clearFrameworks(){
|
||||
mFrameWorks.clear();
|
||||
}
|
||||
@Override
|
||||
public JSONObject toJson() {
|
||||
JSONObject jsonObject=new JSONObject();
|
||||
|
@ -40,9 +40,13 @@
|
||||
addChild(mStringReference);
|
||||
}
|
||||
void onRemoved(){
|
||||
unLinkStringReference(getHeaderBlock().getCommentReference());
|
||||
unLinkStringReference(mNamespaceReference);
|
||||
unLinkStringReference(mStringReference);
|
||||
ResXmlStringPool stringPool = getStringPool();
|
||||
if(stringPool==null){
|
||||
return;
|
||||
}
|
||||
stringPool.removeReference(getHeaderBlock().getCommentReference());
|
||||
stringPool.removeReference(mNamespaceReference);
|
||||
stringPool.removeReference(mStringReference);
|
||||
}
|
||||
void linkStringReferences(){
|
||||
linkStringReference(getHeaderBlock().getCommentReference());
|
||||
@ -68,6 +72,9 @@
|
||||
return getHeaderBlock().getLineNumber().get();
|
||||
}
|
||||
public void setCommentReference(int val){
|
||||
if(val == getCommentReference()){
|
||||
return;
|
||||
}
|
||||
IntegerItem comment=getHeaderBlock().getCommentReference();
|
||||
unLinkStringReference(comment);
|
||||
getHeaderBlock().getCommentReference().set(val);
|
||||
@ -77,6 +84,9 @@
|
||||
return getHeaderBlock().getCommentReference().get();
|
||||
}
|
||||
public void setNamespaceReference(int val){
|
||||
if(val == getNamespaceReference()){
|
||||
return;
|
||||
}
|
||||
unLinkStringReference(mNamespaceReference);
|
||||
mNamespaceReference.set(val);
|
||||
linkStringReference(mNamespaceReference);
|
||||
@ -85,6 +95,9 @@
|
||||
return mNamespaceReference.get();
|
||||
}
|
||||
public void setStringReference(int val){
|
||||
if(val == getStringReference()){
|
||||
return;
|
||||
}
|
||||
unLinkStringReference(mStringReference);
|
||||
mStringReference.set(val);
|
||||
linkStringReference(mStringReference);
|
||||
|
@ -29,6 +29,7 @@
|
||||
import com.reandroid.xml.XMLException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ResXmlAttribute extends ValueItem implements Comparable<ResXmlAttribute>{
|
||||
private ReferenceItem mNSReference;
|
||||
@ -94,6 +95,9 @@
|
||||
setNameReference(xmlID.getIndex());
|
||||
}
|
||||
public void setName(String name, int resourceId){
|
||||
if(Objects.equals(name, getName()) && resourceId==getNameResourceID()){
|
||||
return;
|
||||
}
|
||||
unlink(mNameReference);
|
||||
unLinkNameId(getResXmlID());
|
||||
ResXmlString xmlString = getOrCreateAttributeName(name, resourceId);
|
||||
@ -104,13 +108,34 @@
|
||||
mNameReference = link(OFFSET_NAME);
|
||||
linkNameId();
|
||||
}
|
||||
private void linkStartNameSpace(){
|
||||
ResXmlElement xmlElement=getParentResXmlElement();
|
||||
if(xmlElement==null){
|
||||
return;
|
||||
}
|
||||
ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
|
||||
if(startNamespace==null){
|
||||
return;
|
||||
}
|
||||
startNamespace.addAttributeReference(this);
|
||||
}
|
||||
private void unLinkStartNameSpace(){
|
||||
ResXmlElement xmlElement=getParentResXmlElement();
|
||||
if(xmlElement==null){
|
||||
return;
|
||||
}
|
||||
ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
|
||||
if(startNamespace==null){
|
||||
return;
|
||||
}
|
||||
startNamespace.removeAttributeReference(this);
|
||||
}
|
||||
private ResXmlString getOrCreateAttributeName(String name, int resourceId){
|
||||
StringPool<?> stringPool = getStringPool();
|
||||
ResXmlStringPool stringPool = getStringPool();
|
||||
if(stringPool==null){
|
||||
return null;
|
||||
}
|
||||
ResXmlStringPool resXmlStringPool = (ResXmlStringPool) stringPool;
|
||||
return resXmlStringPool.getOrCreateAttribute(resourceId, name);
|
||||
return stringPool.getOrCreateAttribute(resourceId, name);
|
||||
}
|
||||
public ResXmlElement getParentResXmlElement(){
|
||||
return getParent(ResXmlElement.class);
|
||||
@ -161,6 +186,7 @@
|
||||
unlink(mNSReference);
|
||||
putInteger(getBytesInternal(), OFFSET_NS, ref);
|
||||
mNSReference = link(OFFSET_NS);
|
||||
linkStartNameSpace();
|
||||
}
|
||||
int getNameReference(){
|
||||
return getInteger(getBytesInternal(), OFFSET_NAME);
|
||||
@ -191,17 +217,17 @@
|
||||
public void onReadBytes(BlockReader reader) throws IOException {
|
||||
super.onReadBytes(reader);
|
||||
linkAll();
|
||||
linkStartNameSpace();
|
||||
}
|
||||
@Override
|
||||
public void onRemoved(){
|
||||
super.onRemoved();
|
||||
unLinkStartNameSpace();
|
||||
unlinkAll();
|
||||
}
|
||||
@Override
|
||||
protected void onUnlinkDataString(StringItem stringItem){
|
||||
if(!stringItem.hasReference()){
|
||||
stringItem.set("");
|
||||
}
|
||||
protected void onUnlinkDataString(ReferenceItem referenceItem){
|
||||
unlink(referenceItem);
|
||||
}
|
||||
@Override
|
||||
protected void onDataChanged(){
|
||||
@ -228,6 +254,14 @@
|
||||
}
|
||||
xmlID.removeReference(referenceItem);
|
||||
mNameIdReference = null;
|
||||
if(xmlID.hasReference()){
|
||||
return;
|
||||
}
|
||||
ResXmlIDMap xmlIDMap = getResXmlIDMap();
|
||||
if(xmlIDMap == null){
|
||||
return;
|
||||
}
|
||||
xmlIDMap.removeSafely(xmlID);
|
||||
}
|
||||
private void linkAll(){
|
||||
unlink(mNSReference);
|
||||
@ -270,21 +304,20 @@
|
||||
if(reference == null){
|
||||
return;
|
||||
}
|
||||
StringPool<?> stringPool = getStringPool();
|
||||
ResXmlStringPool stringPool = getStringPool();
|
||||
if(stringPool==null){
|
||||
return;
|
||||
}
|
||||
StringItem stringItem = stringPool.get(reference.get());
|
||||
if(stringItem==null){
|
||||
return;
|
||||
}
|
||||
stringItem.removeReference(reference);
|
||||
if(!stringItem.hasReference()){
|
||||
stringItem.set("");
|
||||
}
|
||||
stringPool.removeReference(reference);
|
||||
}
|
||||
@Override
|
||||
public ResXmlStringPool getStringPool(){
|
||||
StringPool<?> stringPool = super.getStringPool();
|
||||
if(stringPool instanceof ResXmlStringPool){
|
||||
return (ResXmlStringPool) stringPool;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(ResXmlAttribute other) {
|
||||
int id1=getNameResourceID();
|
||||
|
@ -329,14 +329,20 @@
|
||||
return getStartElement().getResXmlAttributeArray().remove(resXmlAttribute);
|
||||
}
|
||||
public boolean removeElement(ResXmlElement element){
|
||||
if(element.getParent()!=null){
|
||||
if(element !=null && element.getParent()!=null){
|
||||
element.onRemoved();
|
||||
}
|
||||
return mBody.remove(element);
|
||||
}
|
||||
public boolean removeNode(ResXmlNode node){
|
||||
if(node instanceof ResXmlElement){
|
||||
return removeElement((ResXmlElement) node);
|
||||
}
|
||||
return mBody.remove(node);
|
||||
}
|
||||
public int countElements(){
|
||||
int result = 0;
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
if(xmlNode instanceof ResXmlElement){
|
||||
result++;
|
||||
}
|
||||
@ -354,11 +360,14 @@
|
||||
}
|
||||
}
|
||||
public List<ResXmlNode> listXmlNodes(){
|
||||
return new ArrayList<>(getXmlNodes());
|
||||
}
|
||||
private List<ResXmlNode> getXmlNodes(){
|
||||
return mBody.getChildes();
|
||||
}
|
||||
public List<ResXmlText> listXmlText(){
|
||||
List<ResXmlText> results=new ArrayList<>();
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
if(xmlNode instanceof ResXmlTextNode){
|
||||
results.add(((ResXmlTextNode) xmlNode).getResXmlText());
|
||||
}
|
||||
@ -367,7 +376,7 @@
|
||||
}
|
||||
public List<ResXmlTextNode> listXmlTextNodes(){
|
||||
List<ResXmlTextNode> results=new ArrayList<>();
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
if(xmlNode instanceof ResXmlTextNode){
|
||||
results.add((ResXmlTextNode) xmlNode);
|
||||
}
|
||||
@ -376,7 +385,7 @@
|
||||
}
|
||||
public List<ResXmlElement> listElements(){
|
||||
List<ResXmlElement> results=new ArrayList<>();
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
if(xmlNode instanceof ResXmlElement){
|
||||
results.add((ResXmlElement) xmlNode);
|
||||
}
|
||||
@ -782,7 +791,7 @@
|
||||
jsonObject.put(NAME_attributes, attrArray);
|
||||
i=0;
|
||||
JSONArray childes=new JSONArray();
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
childes.put(i, xmlNode.toJson());
|
||||
i++;
|
||||
}
|
||||
@ -879,7 +888,7 @@
|
||||
if(comment!=null){
|
||||
xmlElement.addComment(new XMLComment(comment));
|
||||
}
|
||||
for(ResXmlNode xmlNode:listXmlNodes()){
|
||||
for(ResXmlNode xmlNode: getXmlNodes()){
|
||||
if(xmlNode instanceof ResXmlElement){
|
||||
ResXmlElement childResXmlElement=(ResXmlElement)xmlNode;
|
||||
XMLElement childXMLElement =
|
||||
|
@ -20,6 +20,7 @@
|
||||
import com.reandroid.arsc.chunk.Chunk;
|
||||
import com.reandroid.arsc.header.HeaderBlock;
|
||||
import com.reandroid.arsc.item.ResXmlID;
|
||||
import com.reandroid.arsc.item.ResXmlString;
|
||||
import com.reandroid.arsc.pool.ResXmlStringPool;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -31,6 +32,32 @@
|
||||
this.mResXmlIDArray=new ResXmlIDArray(getHeaderBlock());
|
||||
addChild(mResXmlIDArray);
|
||||
}
|
||||
void removeSafely(ResXmlID resXmlID){
|
||||
if(resXmlID==null
|
||||
|| resXmlID.getParent()==null
|
||||
|| resXmlID.getIndex()<0
|
||||
|| resXmlID.hasReference()){
|
||||
return;
|
||||
}
|
||||
ResXmlString xmlString = resXmlID.getResXmlString();
|
||||
if(xmlString == null
|
||||
|| xmlString.getParent()==null
|
||||
|| xmlString.getIndex()<0
|
||||
|| xmlString.hasReference()){
|
||||
return;
|
||||
}
|
||||
ResXmlStringPool stringPool = getXmlStringPool();
|
||||
if(stringPool == null){
|
||||
return;
|
||||
}
|
||||
resXmlID.set(0);
|
||||
ResXmlIDArray idArray = getResXmlIDArray();
|
||||
idArray.remove(resXmlID);
|
||||
stringPool.removeString(xmlString);
|
||||
}
|
||||
public int countId(){
|
||||
return getResXmlIDArray().childesCount();
|
||||
}
|
||||
public void destroy(){
|
||||
getResXmlIDArray().clearChildes();
|
||||
}
|
||||
|
@ -16,15 +16,17 @@
|
||||
package com.reandroid.arsc.chunk.xml;
|
||||
|
||||
import com.reandroid.arsc.chunk.ChunkType;
|
||||
import com.reandroid.arsc.item.ResXmlString;
|
||||
import com.reandroid.xml.SchemaAttr;
|
||||
import com.reandroid.xml.XMLAttribute;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ResXmlStartNamespace extends ResXmlNamespace {
|
||||
private final Set<ResXmlAttribute> mReferencedAttributes;
|
||||
public ResXmlStartNamespace() {
|
||||
super(ChunkType.XML_START_NAMESPACE);
|
||||
this.mReferencedAttributes = new HashSet<>();
|
||||
}
|
||||
public ResXmlEndNamespace getEnd(){
|
||||
return (ResXmlEndNamespace) getPair();
|
||||
@ -46,6 +48,26 @@
|
||||
if(end!=null){
|
||||
end.onRemoved();
|
||||
}
|
||||
mReferencedAttributes.clear();
|
||||
}
|
||||
public boolean hasReferencedAttributes(){
|
||||
return mReferencedAttributes.size()>0;
|
||||
}
|
||||
public void clearReferencedAttributes(){
|
||||
mReferencedAttributes.clear();
|
||||
}
|
||||
public Set<ResXmlAttribute> getReferencedAttributes(){
|
||||
return mReferencedAttributes;
|
||||
}
|
||||
void addAttributeReference(ResXmlAttribute attribute){
|
||||
if(attribute!=null){
|
||||
mReferencedAttributes.add(attribute);
|
||||
}
|
||||
}
|
||||
void removeAttributeReference(ResXmlAttribute attribute){
|
||||
if(attribute!=null){
|
||||
mReferencedAttributes.remove(attribute);
|
||||
}
|
||||
}
|
||||
public XMLAttribute decodeToXml(){
|
||||
String uri=getUri();
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.reandroid.arsc.item;
|
||||
|
||||
import com.reandroid.arsc.base.Block;
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
|
||||
import com.reandroid.arsc.pool.ResXmlStringPool;
|
||||
|
||||
@ -55,7 +54,7 @@ public class ResXmlID extends IntegerItem {
|
||||
}
|
||||
@Override
|
||||
public void onIndexChanged(int oldIndex, int newIndex){
|
||||
reUpdateReferences(newIndex);
|
||||
//TODO: We have to ignore this to avoid conflict with ResXmlIDMap.removeSafely
|
||||
}
|
||||
public String getName(){
|
||||
ResXmlString xmlString = getResXmlString();
|
||||
|
@ -22,10 +22,7 @@ import com.reandroid.arsc.array.StyleArray;
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlIDMap;
|
||||
import com.reandroid.arsc.group.StringGroup;
|
||||
import com.reandroid.arsc.item.IntegerArray;
|
||||
import com.reandroid.arsc.item.IntegerItem;
|
||||
import com.reandroid.arsc.item.ResXmlID;
|
||||
import com.reandroid.arsc.item.ResXmlString;
|
||||
import com.reandroid.arsc.item.*;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -34,6 +31,30 @@ import java.util.Objects;
|
||||
super(is_utf8);
|
||||
}
|
||||
@Override
|
||||
public ResXmlString removeReference(ReferenceItem referenceItem){
|
||||
if(referenceItem==null){
|
||||
return null;
|
||||
}
|
||||
ResXmlString stringItem = super.removeReference(referenceItem);
|
||||
removeNotUsedItem(stringItem);
|
||||
return stringItem;
|
||||
}
|
||||
private void removeNotUsedItem(ResXmlString xmlString){
|
||||
if(xmlString == null || xmlString.hasReference()){
|
||||
return;
|
||||
}
|
||||
ResXmlIDMap idMap = getResXmlIDMap();
|
||||
int lastIdIndex = -1;
|
||||
if(idMap!=null){
|
||||
lastIdIndex = idMap.countId() - 1;
|
||||
}
|
||||
if(idMap!=null && xmlString.getIndex()>lastIdIndex){
|
||||
removeString(xmlString);
|
||||
}else {
|
||||
xmlString.set("");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
StringArray<ResXmlString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||
return new ResXmlStringArray(offsets, itemCount, itemStart, is_utf8);
|
||||
}
|
||||
|
@ -68,6 +68,9 @@ package com.reandroid.arsc.pool;
|
||||
|
||||
mUniqueMap = new HashMap<>();
|
||||
}
|
||||
public void removeString(T item){
|
||||
getStringsArray().remove(item);
|
||||
}
|
||||
public void destroy(){
|
||||
getStyleArray().clearChildes();
|
||||
getStringsArray().clearChildes();
|
||||
|
@ -27,6 +27,7 @@ import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class ValueItem extends BlockItem implements Value,
|
||||
JSONConvert<JSONObject>{
|
||||
@ -150,16 +151,14 @@ import java.io.IOException;
|
||||
return;
|
||||
}
|
||||
mStringReference = null;
|
||||
onUnlinkDataString(stringReference);
|
||||
}
|
||||
protected void onUnlinkDataString(ReferenceItem referenceItem){
|
||||
StringPool<?> stringPool = getStringPool();
|
||||
if(stringPool == null){
|
||||
return;
|
||||
}
|
||||
StringItem stringItem = stringPool.removeReference(stringReference);
|
||||
if(stringItem!=null){
|
||||
onUnlinkDataString(stringItem);
|
||||
}
|
||||
}
|
||||
protected void onUnlinkDataString(StringItem stringItem){
|
||||
stringPool.removeReference(referenceItem);
|
||||
}
|
||||
public StringPool<?> getStringPool(){
|
||||
Block parent = getParent();
|
||||
@ -204,6 +203,10 @@ import java.io.IOException;
|
||||
return null;
|
||||
}
|
||||
public void setValueAsString(String str){
|
||||
if(getValueType() != ValueType.STRING
|
||||
&& Objects.equals(str, getValueAsString())){
|
||||
return;
|
||||
}
|
||||
StringItem stringItem = getStringPool().getOrCreate(str);
|
||||
setData(stringItem.getIndex());
|
||||
setValueType(ValueType.STRING);
|
||||
|
Loading…
x
Reference in New Issue
Block a user