[XML] clean unused strings and res id from pool

This commit is contained in:
REAndroid 2023-03-12 14:11:43 -04:00
parent 9914722bac
commit dfe85947b4
12 changed files with 214 additions and 45 deletions

View File

@ -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());
}

View File

@ -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()){

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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 =

View File

@ -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();
}

View File

@ -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();

View File

@ -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();

View File

@ -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);
}

View File

@ -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();

View File

@ -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);