diff --git a/src/main/java/com/reandroid/arsc/array/EntryArray.java b/src/main/java/com/reandroid/arsc/array/EntryArray.java index 2935670..efab520 100755 --- a/src/main/java/com/reandroid/arsc/array/EntryArray.java +++ b/src/main/java/com/reandroid/arsc/array/EntryArray.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 implements JSONConvert itr = iterator(true); + while (itr.hasNext()){ + Entry entry = itr.next(); + entry.linkTableStringsInternal(tableStringPool); + } + } + public void linkSpecStringsInternal(SpecStringPool specStringPool){ + Iterator itr = iterator(true); + while (itr.hasNext()){ + Entry entry = itr.next(); + entry.linkSpecStringsInternal(specStringPool); + } + } public int getHighestEntryId(){ if(isSparse()){ return ((SparseOffsetsArray) getOffsetArray()).getHighestId(); diff --git a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java index 4ddf940..0ed69f5 100755 --- a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java @@ -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 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 if(!this.entryGroupMapLocked){ return; } + entryGroupMapLocked = false; Map map = this.mEntriesGroup; map.clear(); createEntryGroupMap(map); diff --git a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java index ce6e13d..7f6f2d6 100755 --- a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java @@ -53,6 +53,11 @@ public class TableBlock extends Chunk addChild(mPackageArray); } + public void linkTableStringsInternal(TableStringPool tableStringPool){ + for(PackageBlock packageBlock : listPackages()){ + packageBlock.linkTableStringsInternal(tableStringPool); + } + } public List resolveReference(int referenceId){ return resolveReference(referenceId, null); } diff --git a/src/main/java/com/reandroid/arsc/chunk/TypeBlock.java b/src/main/java/com/reandroid/arsc/chunk/TypeBlock.java index f382836..b603205 100755 --- a/src/main/java/com/reandroid/arsc/chunk/TypeBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/TypeBlock.java @@ -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 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(); } diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java index ce3b119..991bcbf 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java @@ -1,489 +1,490 @@ - /* - * 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.xml; +/* + * 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.xml; - import com.reandroid.arsc.decoder.ValueDecoder; - import com.reandroid.arsc.group.EntryGroup; - import com.reandroid.arsc.io.BlockReader; - import com.reandroid.arsc.item.*; - import com.reandroid.arsc.pool.ResXmlStringPool; - import com.reandroid.arsc.pool.StringPool; - import com.reandroid.arsc.value.AttributeValue; - import com.reandroid.arsc.value.ValueItem; - import com.reandroid.arsc.value.ValueType; - import com.reandroid.common.EntryStore; - import com.reandroid.json.JSONObject; - import com.reandroid.xml.XMLAttribute; - import com.reandroid.xml.XMLException; +import com.reandroid.arsc.decoder.ValueDecoder; +import com.reandroid.arsc.group.EntryGroup; +import com.reandroid.arsc.io.BlockReader; +import com.reandroid.arsc.item.*; +import com.reandroid.arsc.pool.ResXmlStringPool; +import com.reandroid.arsc.pool.StringPool; +import com.reandroid.arsc.value.AttributeValue; +import com.reandroid.arsc.value.ValueItem; +import com.reandroid.arsc.value.ValueType; +import com.reandroid.common.EntryStore; +import com.reandroid.json.JSONObject; +import com.reandroid.xml.XMLAttribute; +import com.reandroid.xml.XMLException; - import java.io.IOException; - import java.util.Objects; +import java.io.IOException; +import java.util.Objects; - public class ResXmlAttribute extends ValueItem implements AttributeValue, Comparable{ - private ReferenceItem mNSReference; - private ReferenceItem mNameReference; - private ReferenceItem mNameIdReference; - private ReferenceItem mValueStringReference; - public ResXmlAttribute(int attributeUnitSize) { - super(attributeUnitSize, OFFSET_SIZE); - byte[] bts = getBytesInternal(); - putInteger(bts, OFFSET_NS, -1); - putInteger(bts, OFFSET_NAME, -1); - putInteger(bts, OFFSET_STRING, -1); - } - public ResXmlAttribute() { - this(20); - } +public class ResXmlAttribute extends ValueItem implements AttributeValue, Comparable{ + private ReferenceItem mNSReference; + private ReferenceItem mNameReference; + private ReferenceItem mNameIdReference; + private ReferenceItem mValueStringReference; + public ResXmlAttribute(int attributeUnitSize) { + super(attributeUnitSize, OFFSET_SIZE); + byte[] bts = getBytesInternal(); + putInteger(bts, OFFSET_NS, -1); + putInteger(bts, OFFSET_NAME, -1); + putInteger(bts, OFFSET_STRING, -1); + } + public ResXmlAttribute() { + this(20); + } - public String getUri(){ - return getString(getNamespaceReference()); - } - public String getFullName(){ - String name=getName(); - if(name==null){ - return null; - } - String prefix=getNamePrefix(); - if(prefix==null){ - return name; - } - return prefix+":"+name; - } - public String getName(){ - return getString(getNameReference()); - } - public String getNamePrefix(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement==null){ - return null; - } - ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); - if(startNamespace==null){ - return null; - } - return startNamespace.getPrefix(); - } - // WARN! Careful this is not real value - public String getValueString(){ - return getString(getValueStringReference()); - } - @Override - public int getNameResourceID(){ - ResXmlID xmlID = getResXmlID(); - if(xmlID != null){ - return xmlID.get(); - } - return 0; - } - @Override - public void setNameResourceID(int resourceId){ - ResXmlIDMap xmlIDMap=getResXmlIDMap(); - if(xmlIDMap==null){ - return; - } - ResXmlID xmlID = xmlIDMap.getOrCreate(resourceId); - 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); - if(xmlString==null){ - return; - } - setNameReference(xmlString.getIndex()); - 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){ - ResXmlStringPool stringPool = getStringPool(); - if(stringPool==null){ - return null; - } - return stringPool.getOrCreateAttribute(resourceId, name); - } - public ResXmlElement getParentResXmlElement(){ - return getParent(ResXmlElement.class); - } - public int getAttributesUnitSize(){ - return OFFSET_SIZE + super.getSize(); - } - public void setAttributesUnitSize(int size){ - int eight = size - OFFSET_SIZE; - super.setSize(eight); - } - private String getString(int ref){ - if(ref<0){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - StringItem stringItem = stringPool.get(ref); - if(stringItem == null){ - return null; - } - return stringItem.getHtml(); - } - private ResXmlID getResXmlID(){ - ResXmlIDMap xmlIDMap = getResXmlIDMap(); - if(xmlIDMap == null){ - return null; - } - return xmlIDMap.getResXmlIDArray().get(getNameReference()); - } - private ResXmlIDMap getResXmlIDMap(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement!=null){ - return xmlElement.getResXmlIDMap(); - } - return null; - } + public String getUri(){ + return getString(getNamespaceReference()); + } + public String getFullName(){ + String name=getName(); + if(name==null){ + return null; + } + String prefix=getNamePrefix(); + if(prefix==null){ + return name; + } + return prefix+":"+name; + } + public String getName(){ + return getString(getNameReference()); + } + public String getNamePrefix(){ + ResXmlElement xmlElement=getParentResXmlElement(); + if(xmlElement==null){ + return null; + } + ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); + if(startNamespace==null){ + return null; + } + return startNamespace.getPrefix(); + } + // WARN! Careful this is not real value + public String getValueString(){ + return getString(getValueStringReference()); + } + @Override + public int getNameResourceID(){ + ResXmlID xmlID = getResXmlID(); + if(xmlID != null){ + return xmlID.get(); + } + return 0; + } + @Override + public void setNameResourceID(int resourceId){ + ResXmlIDMap xmlIDMap=getResXmlIDMap(); + if(xmlIDMap==null){ + return; + } + ResXmlID xmlID = xmlIDMap.getOrCreate(resourceId); + 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); + if(xmlString==null){ + return; + } + setNameReference(xmlString.getIndex()); + 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){ + ResXmlStringPool stringPool = getStringPool(); + if(stringPool==null){ + return null; + } + return stringPool.getOrCreateAttribute(resourceId, name); + } + public ResXmlElement getParentResXmlElement(){ + return getParent(ResXmlElement.class); + } + public int getAttributesUnitSize(){ + return OFFSET_SIZE + super.getSize(); + } + public void setAttributesUnitSize(int size){ + int eight = size - OFFSET_SIZE; + super.setSize(eight); + } + private String getString(int ref){ + if(ref<0){ + return null; + } + StringPool stringPool = getStringPool(); + if(stringPool == null){ + return null; + } + StringItem stringItem = stringPool.get(ref); + if(stringItem == null){ + return null; + } + return stringItem.getHtml(); + } + private ResXmlID getResXmlID(){ + ResXmlIDMap xmlIDMap = getResXmlIDMap(); + if(xmlIDMap == null){ + return null; + } + return xmlIDMap.getResXmlIDArray().get(getNameReference()); + } + private ResXmlIDMap getResXmlIDMap(){ + ResXmlElement xmlElement=getParentResXmlElement(); + if(xmlElement!=null){ + return xmlElement.getResXmlIDMap(); + } + return null; + } - int getNamespaceReference(){ - return getInteger(getBytesInternal(), OFFSET_NS); - } - public void setNamespaceReference(int ref){ - if(ref == getNamespaceReference()){ - return; - } - unlink(mNSReference); - putInteger(getBytesInternal(), OFFSET_NS, ref); - mNSReference = link(OFFSET_NS); - linkStartNameSpace(); - } - int getNameReference(){ - return getInteger(getBytesInternal(), OFFSET_NAME); - } - void setNameReference(int ref){ - if(ref == getNameReference()){ - return; - } - unLinkNameId(getResXmlID()); - unlink(mNameReference); - putInteger(getBytesInternal(), OFFSET_NAME, ref); - mNameReference = link(OFFSET_NAME); - linkNameId(); - } - int getValueStringReference(){ - return getInteger(getBytesInternal(), OFFSET_STRING); - } - void setValueStringReference(int ref){ - if(ref == getValueStringReference() && mValueStringReference!=null){ - return; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return; - } - StringItem stringItem = stringPool.get(ref); - unlink(mValueStringReference); - if(stringItem!=null){ - ref = stringItem.getIndex(); - } - putInteger(getBytesInternal(), OFFSET_STRING, ref); - ReferenceItem referenceItem = null; - if(stringItem!=null){ - referenceItem = new ReferenceBlock<>(this, OFFSET_STRING); - stringItem.addReference(referenceItem); - } - mValueStringReference = referenceItem; - } + int getNamespaceReference(){ + return getInteger(getBytesInternal(), OFFSET_NS); + } + public void setNamespaceReference(int ref){ + if(ref == getNamespaceReference()){ + return; + } + unlink(mNSReference); + putInteger(getBytesInternal(), OFFSET_NS, ref); + mNSReference = link(OFFSET_NS); + linkStartNameSpace(); + } + int getNameReference(){ + return getInteger(getBytesInternal(), OFFSET_NAME); + } + void setNameReference(int ref){ + if(ref == getNameReference()){ + return; + } + unLinkNameId(getResXmlID()); + unlink(mNameReference); + putInteger(getBytesInternal(), OFFSET_NAME, ref); + mNameReference = link(OFFSET_NAME); + linkNameId(); + } + int getValueStringReference(){ + return getInteger(getBytesInternal(), OFFSET_STRING); + } + void setValueStringReference(int ref){ + if(ref == getValueStringReference() && mValueStringReference!=null){ + return; + } + StringPool stringPool = getStringPool(); + if(stringPool == null){ + return; + } + StringItem stringItem = stringPool.get(ref); + unlink(mValueStringReference); + if(stringItem!=null){ + ref = stringItem.getIndex(); + } + putInteger(getBytesInternal(), OFFSET_STRING, ref); + ReferenceItem referenceItem = null; + if(stringItem!=null){ + referenceItem = new ReferenceBlock<>(this, OFFSET_STRING); + stringItem.addReference(referenceItem); + } + mValueStringReference = referenceItem; + } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - super.onReadBytes(reader); - linkAll(); - linkStartNameSpace(); - } - @Override - public void onRemoved(){ - super.onRemoved(); - unLinkStartNameSpace(); - unlinkAll(); - } - @Override - protected void onUnlinkDataString(ReferenceItem referenceItem){ - unlink(referenceItem); - } - @Override - protected void onDataChanged(){ - if(getValueType()==ValueType.STRING){ - setValueStringReference(getData()); - }else { - setValueStringReference(-1); - } - } - @Override - public ResXmlDocument getParentChunk() { - ResXmlElement element = getParentResXmlElement(); - if(element!=null){ - return element.getParentDocument(); - } - return null; - } + @Override + public void onReadBytes(BlockReader reader) throws IOException { + super.onReadBytes(reader); + super.onDataLoaded(); + linkAll(); + linkStartNameSpace(); + } + @Override + public void onRemoved(){ + super.onRemoved(); + unLinkStartNameSpace(); + unlinkAll(); + } + @Override + protected void onUnlinkDataString(ReferenceItem referenceItem){ + unlink(referenceItem); + } + @Override + protected void onDataChanged(){ + if(getValueType()==ValueType.STRING){ + setValueStringReference(getData()); + }else { + setValueStringReference(-1); + } + } + @Override + public ResXmlDocument getParentChunk() { + ResXmlElement element = getParentResXmlElement(); + if(element!=null){ + return element.getParentDocument(); + } + return null; + } - private void linkNameId(){ - ResXmlID xmlID = getResXmlID(); - if(xmlID==null){ - return; - } - unLinkNameId(xmlID); - ReferenceItem referenceItem = new ReferenceBlock<>(this, OFFSET_NAME); - xmlID.addReference(referenceItem); - mNameIdReference = referenceItem; - } - private void unLinkNameId(ResXmlID xmlID){ - ReferenceItem referenceItem = mNameIdReference; - if(referenceItem==null || xmlID == null){ - return; - } - xmlID.removeReference(referenceItem); - mNameIdReference = null; - if(xmlID.hasReference()){ - return; - } - ResXmlIDMap xmlIDMap = getResXmlIDMap(); - if(xmlIDMap == null){ - return; - } - xmlIDMap.removeSafely(xmlID); - } - private void linkAll(){ - unlink(mNSReference); - mNSReference = link(OFFSET_NS); - unlink(mNameReference); - mNameReference = link(OFFSET_NAME); - unlink(mValueStringReference); - mValueStringReference = link(OFFSET_STRING); + private void linkNameId(){ + ResXmlID xmlID = getResXmlID(); + if(xmlID==null){ + return; + } + unLinkNameId(xmlID); + ReferenceItem referenceItem = new ReferenceBlock<>(this, OFFSET_NAME); + xmlID.addReference(referenceItem); + mNameIdReference = referenceItem; + } + private void unLinkNameId(ResXmlID xmlID){ + ReferenceItem referenceItem = mNameIdReference; + if(referenceItem==null || xmlID == null){ + return; + } + xmlID.removeReference(referenceItem); + mNameIdReference = null; + if(xmlID.hasReference()){ + return; + } + ResXmlIDMap xmlIDMap = getResXmlIDMap(); + if(xmlIDMap == null){ + return; + } + xmlIDMap.removeSafely(xmlID); + } + private void linkAll(){ + unlink(mNSReference); + mNSReference = link(OFFSET_NS); + unlink(mNameReference); + mNameReference = link(OFFSET_NAME); + unlink(mValueStringReference); + mValueStringReference = link(OFFSET_STRING); - linkNameId(); - } - private void unlinkAll(){ - unlink(mNSReference); - unlink(mNameReference); - unlink(mValueStringReference); - mNSReference = null; - mNameReference = null; - mValueStringReference = null; + linkNameId(); + } + private void unlinkAll(){ + unlink(mNSReference); + unlink(mNameReference); + unlink(mValueStringReference); + mNSReference = null; + mNameReference = null; + mValueStringReference = null; - unLinkNameId(getResXmlID()); - } - private ReferenceItem link(int offset){ - if(offset<0){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - int ref = getInteger(getBytesInternal(), offset); - StringItem stringItem = stringPool.get(ref); - if(stringItem == null){ - return null; - } - ReferenceItem referenceItem = new ReferenceBlock<>(this, offset); - stringItem.addReference(referenceItem); - return referenceItem; - } - private void unlink(ReferenceItem reference){ - if(reference == null){ - return; - } - ResXmlStringPool stringPool = getStringPool(); - if(stringPool==null){ - return; - } - 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(); - int id2=other.getNameResourceID(); - if(id1==0 && id2!=0){ - return 1; - } - if(id2==0 && id1!=0){ - return -1; - } - if(id1!=0){ - return Integer.compare(id1, id2); - } - String name1=getName(); - if(name1==null){ - name1=""; - } - String name2=other.getName(); - if(name2==null){ - name2=""; - } - return name1.compareTo(name2); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject= new JSONObject(); - jsonObject.put(NAME_name, getName()); - jsonObject.put(NAME_id, getNameResourceID()); - jsonObject.put(NAME_namespace_uri, getUri()); - ValueType valueType=getValueType(); - jsonObject.put(NAME_value_type, valueType.name()); - if(valueType==ValueType.STRING){ - jsonObject.put(NAME_data, getValueAsString()); - }else if(valueType==ValueType.INT_BOOLEAN){ - jsonObject.put(NAME_data, getValueAsBoolean()); - }else { - jsonObject.put(NAME_data, getData()); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - String name = json.optString(NAME_name, ""); - int id = json.optInt(NAME_id, 0); - setName(name, id); - String uri= json.optString(NAME_namespace_uri, null); - if(uri!=null){ - ResXmlStartNamespace ns = getParentResXmlElement().getStartNamespaceByUri(uri); - if(ns==null){ - ns = getParentResXmlElement().getRootResXmlElement() - .getOrCreateNamespace(uri, ""); - } - setNamespaceReference(ns.getUriReference()); - } - ValueType valueType=ValueType.fromName(json.getString(NAME_value_type)); - if(valueType==ValueType.STRING){ - setValueAsString(json.optString(NAME_data, "")); - }else if(valueType==ValueType.INT_BOOLEAN){ - setValueAsBoolean(json.getBoolean(NAME_data)); - }else { - setValueType(valueType); - setData(json.getInt(NAME_data)); - } - } - public XMLAttribute decodeToXml(EntryStore entryStore, int currentPackageId) throws XMLException { - int resourceId=getNameResourceID(); - String name; - if(resourceId==0){ - name=getName(); - }else { - EntryGroup group = entryStore.getEntryGroup(resourceId); - if(group==null){ - //Lets ignore such error until XML encoder implemented - //throw new XMLException("Failed to decode attribute name: " - //+ String.format("@0x%08x", resourceId)); - name=String.format("@0x%08x", resourceId); - }else { - name=group.getSpecName(); - } - } - String prefix = getNamePrefix(); - if(prefix!=null){ - name=prefix+":"+name; - } - ValueType valueType = getValueType(); - int raw = getData(); - String value = ValueDecoder.decode(entryStore, currentPackageId, (AttributeValue) this); - XMLAttribute attribute = new XMLAttribute(name, value); - attribute.setNameId(resourceId); - if(valueType==ValueType.REFERENCE||valueType==ValueType.ATTRIBUTE){ - attribute.setValueId(raw); - } - return attribute; - } - @Override - public String toString(){ - String fullName = getFullName(); - if(fullName!=null ){ - int id=getNameResourceID(); - if(id!=0){ - fullName=fullName+"(@"+String.format("0x%08x",id)+")"; - } - String valStr; - ValueType valueType=getValueType(); - if(valueType==ValueType.STRING){ - valStr=getValueAsString(); - }else if (valueType==ValueType.INT_BOOLEAN){ - valStr = String.valueOf(getValueAsBoolean()); - }else if (valueType==ValueType.INT_DEC){ - valStr = String.valueOf(getData()); - }else { - valStr = "["+valueType+"] " + String.format("0x%08x",getData()); - } - if(valStr!=null){ - return fullName+"=\""+valStr+"\""; - } - return fullName+"["+valueType+"]=\""+ getData()+"\""; - } - StringBuilder builder= new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": "); - builder.append(getIndex()); - builder.append("{NamespaceReference=").append(getNamespaceReference()); - builder.append(", NameReference=").append(getNameReference()); - builder.append(", ValueStringReference=").append(getValueStringReference()); - builder.append(", ValueSize=").append(getSize()); - builder.append(", ValueTypeByte=").append(getType() & 0xff); - builder.append(", Data=").append(getData()); - builder.append("}"); - return builder.toString(); - } + unLinkNameId(getResXmlID()); + } + private ReferenceItem link(int offset){ + if(offset<0){ + return null; + } + StringPool stringPool = getStringPool(); + if(stringPool == null){ + return null; + } + int ref = getInteger(getBytesInternal(), offset); + StringItem stringItem = stringPool.get(ref); + if(stringItem == null){ + return null; + } + ReferenceItem referenceItem = new ReferenceBlock<>(this, offset); + stringItem.addReference(referenceItem); + return referenceItem; + } + private void unlink(ReferenceItem reference){ + if(reference == null){ + return; + } + ResXmlStringPool stringPool = getStringPool(); + if(stringPool==null){ + return; + } + 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(); + int id2=other.getNameResourceID(); + if(id1==0 && id2!=0){ + return 1; + } + if(id2==0 && id1!=0){ + return -1; + } + if(id1!=0){ + return Integer.compare(id1, id2); + } + String name1=getName(); + if(name1==null){ + name1=""; + } + String name2=other.getName(); + if(name2==null){ + name2=""; + } + return name1.compareTo(name2); + } + @Override + public JSONObject toJson() { + JSONObject jsonObject= new JSONObject(); + jsonObject.put(NAME_name, getName()); + jsonObject.put(NAME_id, getNameResourceID()); + jsonObject.put(NAME_namespace_uri, getUri()); + ValueType valueType=getValueType(); + jsonObject.put(NAME_value_type, valueType.name()); + if(valueType==ValueType.STRING){ + jsonObject.put(NAME_data, getValueAsString()); + }else if(valueType==ValueType.INT_BOOLEAN){ + jsonObject.put(NAME_data, getValueAsBoolean()); + }else { + jsonObject.put(NAME_data, getData()); + } + return jsonObject; + } + @Override + public void fromJson(JSONObject json) { + String name = json.optString(NAME_name, ""); + int id = json.optInt(NAME_id, 0); + setName(name, id); + String uri= json.optString(NAME_namespace_uri, null); + if(uri!=null){ + ResXmlStartNamespace ns = getParentResXmlElement().getStartNamespaceByUri(uri); + if(ns==null){ + ns = getParentResXmlElement().getRootResXmlElement() + .getOrCreateNamespace(uri, ""); + } + setNamespaceReference(ns.getUriReference()); + } + ValueType valueType=ValueType.fromName(json.getString(NAME_value_type)); + if(valueType==ValueType.STRING){ + setValueAsString(json.optString(NAME_data, "")); + }else if(valueType==ValueType.INT_BOOLEAN){ + setValueAsBoolean(json.getBoolean(NAME_data)); + }else { + setValueType(valueType); + setData(json.getInt(NAME_data)); + } + } + public XMLAttribute decodeToXml(EntryStore entryStore, int currentPackageId) throws XMLException { + int resourceId=getNameResourceID(); + String name; + if(resourceId==0){ + name=getName(); + }else { + EntryGroup group = entryStore.getEntryGroup(resourceId); + if(group==null){ + //Lets ignore such error until XML encoder implemented + //throw new XMLException("Failed to decode attribute name: " + //+ String.format("@0x%08x", resourceId)); + name=String.format("@0x%08x", resourceId); + }else { + name=group.getSpecName(); + } + } + String prefix = getNamePrefix(); + if(prefix!=null){ + name=prefix+":"+name; + } + ValueType valueType = getValueType(); + int raw = getData(); + String value = ValueDecoder.decode(entryStore, currentPackageId, (AttributeValue) this); + XMLAttribute attribute = new XMLAttribute(name, value); + attribute.setNameId(resourceId); + if(valueType==ValueType.REFERENCE||valueType==ValueType.ATTRIBUTE){ + attribute.setValueId(raw); + } + return attribute; + } + @Override + public String toString(){ + String fullName = getFullName(); + if(fullName!=null ){ + int id=getNameResourceID(); + if(id!=0){ + fullName=fullName+"(@"+String.format("0x%08x",id)+")"; + } + String valStr; + ValueType valueType=getValueType(); + if(valueType==ValueType.STRING){ + valStr=getValueAsString(); + }else if (valueType==ValueType.INT_BOOLEAN){ + valStr = String.valueOf(getValueAsBoolean()); + }else if (valueType==ValueType.INT_DEC){ + valStr = String.valueOf(getData()); + }else { + valStr = "["+valueType+"] " + String.format("0x%08x",getData()); + } + if(valStr!=null){ + return fullName+"=\""+valStr+"\""; + } + return fullName+"["+valueType+"]=\""+ getData()+"\""; + } + StringBuilder builder= new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append(": "); + builder.append(getIndex()); + builder.append("{NamespaceReference=").append(getNamespaceReference()); + builder.append(", NameReference=").append(getNameReference()); + builder.append(", ValueStringReference=").append(getValueStringReference()); + builder.append(", ValueSize=").append(getSize()); + builder.append(", ValueTypeByte=").append(getType() & 0xff); + builder.append(", Data=").append(getData()); + builder.append("}"); + return builder.toString(); + } - public static final String NAME_id = "id"; - public static final String NAME_name = "name"; - public static final String NAME_namespace_uri = "namespace_uri"; + public static final String NAME_id = "id"; + public static final String NAME_name = "name"; + public static final String NAME_namespace_uri = "namespace_uri"; - private static final int OFFSET_NS = 0; - private static final int OFFSET_NAME = 4; - private static final int OFFSET_STRING = 8; + private static final int OFFSET_NS = 0; + private static final int OFFSET_NAME = 4; + private static final int OFFSET_STRING = 8; - private static final int OFFSET_SIZE = 12; - } + private static final int OFFSET_SIZE = 12; +} diff --git a/src/main/java/com/reandroid/arsc/container/SpecTypePair.java b/src/main/java/com/reandroid/arsc/container/SpecTypePair.java index ed688d5..d23ed02 100755 --- a/src/main/java/com/reandroid/arsc/container/SpecTypePair.java +++ b/src/main/java/com/reandroid/arsc/container/SpecTypePair.java @@ -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 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 createEntryGroups(){ Map map = new HashMap<>(); for(TypeBlock typeBlock:listTypeBlocks()){ diff --git a/src/main/java/com/reandroid/arsc/item/ResXmlString.java b/src/main/java/com/reandroid/arsc/item/ResXmlString.java index 5e65127..3cacfb8 100755 --- a/src/main/java/com/reandroid/arsc/item/ResXmlString.java +++ b/src/main/java/com/reandroid/arsc/item/ResXmlString.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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(){ + } } diff --git a/src/main/java/com/reandroid/arsc/item/StringItem.java b/src/main/java/com/reandroid/arsc/item/StringItem.java index d237762..1e6269e 100755 --- a/src/main/java/com/reandroid/arsc/item/StringItem.java +++ b/src/main/java/com/reandroid/arsc/item/StringItem.java @@ -49,11 +49,19 @@ public class StringItem extends BlockItem implements JSONConvert { mReferencedList.clear(); } public boolean hasReference(){ + ensureStringLinkUnlocked(); return mReferencedList.size()>0; } public Collection 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); @@ -265,11 +273,11 @@ public class StringItem extends BlockItem implements JSONConvert { } @Override public String toString(){ - String str=getHtml(); - if(str==null){ + String str = getHtml(); + if(str == null){ return "NULL"; } - return "USED BY="+getReferencedList().size()+"{"+str+"}"; + return "USED BY=" + mReferencedList.size() + "{" + str + "}"; } private static int[] decodeUtf8StringByteLength(byte[] lengthBytes) { diff --git a/src/main/java/com/reandroid/arsc/item/TableString.java b/src/main/java/com/reandroid/arsc/item/TableString.java index b82f336..143aaa5 100755 --- a/src/main/java/com/reandroid/arsc/item/TableString.java +++ b/src/main/java/com/reandroid/arsc/item/TableString.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/main/java/com/reandroid/arsc/item/TypeString.java b/src/main/java/com/reandroid/arsc/item/TypeString.java index 50037b6..6aefa0a 100755 --- a/src/main/java/com/reandroid/arsc/item/TypeString.java +++ b/src/main/java/com/reandroid/arsc/item/TypeString.java @@ -1,24 +1,24 @@ - /* - * 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. - */ +/* + * 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.item; - import com.reandroid.arsc.pool.TypeStringPool; +import com.reandroid.arsc.pool.TypeStringPool; - public class TypeString extends StringItem { +public class TypeString extends StringItem { public TypeString(boolean utf8) { super(utf8); } @@ -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(); } diff --git a/src/main/java/com/reandroid/arsc/pool/ResXmlStringPool.java b/src/main/java/com/reandroid/arsc/pool/ResXmlStringPool.java index 594d457..df2ab5c 100755 --- a/src/main/java/com/reandroid/arsc/pool/ResXmlStringPool.java +++ b/src/main/java/com/reandroid/arsc/pool/ResXmlStringPool.java @@ -25,7 +25,7 @@ import java.util.Objects; public class ResXmlStringPool extends StringPool { public ResXmlStringPool(boolean is_utf8) { - super(is_utf8); + super(is_utf8, false); } @Override public ResXmlString removeReference(ReferenceItem referenceItem){ diff --git a/src/main/java/com/reandroid/arsc/pool/SpecStringPool.java b/src/main/java/com/reandroid/arsc/pool/SpecStringPool.java index 758ebaf..a7ec8ae 100755 --- a/src/main/java/com/reandroid/arsc/pool/SpecStringPool.java +++ b/src/main/java/com/reandroid/arsc/pool/SpecStringPool.java @@ -34,4 +34,12 @@ public class SpecStringPool extends StringPool { public PackageBlock getPackageBlock(){ return getParent(PackageBlock.class); } + + @Override + void linkStrings(){ + PackageBlock packageBlock = getPackageBlock(); + if(packageBlock != null){ + packageBlock.linkSpecStringsInternal(this); + } + } } diff --git a/src/main/java/com/reandroid/arsc/pool/StringPool.java b/src/main/java/com/reandroid/arsc/pool/StringPool.java index ffed592..1f1cf46 100755 --- a/src/main/java/com/reandroid/arsc/pool/StringPool.java +++ b/src/main/java/com/reandroid/arsc/pool/StringPool.java @@ -33,12 +33,14 @@ import java.util.*; public abstract class StringPool extends Chunk implements BlockLoad, JSONConvert, Comparator { + private final Object mLock = new Object(); private final StringArray mArrayStrings; private final StyleArray mArrayStyles; private final Map> 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 extends Chunk(); + 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); } diff --git a/src/main/java/com/reandroid/arsc/pool/TableStringPool.java b/src/main/java/com/reandroid/arsc/pool/TableStringPool.java index 47e5c68..0248189 100755 --- a/src/main/java/com/reandroid/arsc/pool/TableStringPool.java +++ b/src/main/java/com/reandroid/arsc/pool/TableStringPool.java @@ -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 { super(is_utf8); } + @Override + void linkStrings(){ + TableBlock tableBlock = getParentInstance(TableBlock.class); + if(tableBlock != null){ + tableBlock.linkTableStringsInternal(this); + } + } @Override StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { return new TableStringArray(offsets, itemCount, itemStart, is_utf8); diff --git a/src/main/java/com/reandroid/arsc/pool/TypeStringPool.java b/src/main/java/com/reandroid/arsc/pool/TypeStringPool.java index 1893df0..ce08837 100755 --- a/src/main/java/com/reandroid/arsc/pool/TypeStringPool.java +++ b/src/main/java/com/reandroid/arsc/pool/TypeStringPool.java @@ -27,7 +27,7 @@ import com.reandroid.arsc.item.TypeString; public class TypeStringPool extends StringPool { 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){ diff --git a/src/main/java/com/reandroid/arsc/value/Entry.java b/src/main/java/com/reandroid/arsc/value/Entry.java index 2739ab4..0b7a276 100755 --- a/src/main/java/com/reandroid/arsc/value/Entry.java +++ b/src/main/java/com/reandroid/arsc/value/Entry.java @@ -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 { 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){ diff --git a/src/main/java/com/reandroid/arsc/value/ResTableEntry.java b/src/main/java/com/reandroid/arsc/value/ResTableEntry.java index f72678b..e3d505c 100644 --- a/src/main/java/com/reandroid/arsc/value/ResTableEntry.java +++ b/src/main/java/com/reandroid/arsc/value/ResTableEntry.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 { @@ -22,6 +23,10 @@ public class ResTableEntry extends TableEntry { super(new EntryHeader(), new ResValue()); } + @Override + void linkTableStringsInternal(TableStringPool tableStringPool){ + getValue().linkTableStrings(tableStringPool); + } @Override void onRemoved(){ getHeader().onRemoved(); diff --git a/src/main/java/com/reandroid/arsc/value/ResTableMapEntry.java b/src/main/java/com/reandroid/arsc/value/ResTableMapEntry.java index c08a188..5c63e46 100644 --- a/src/main/java/com/reandroid/arsc/value/ResTableMapEntry.java +++ b/src/main/java/com/reandroid/arsc/value/ResTableMapEntry.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 { @@ -42,6 +43,12 @@ public class ResTableMapEntry extends TableEntry tableEntry); + abstract void linkTableStringsInternal(TableStringPool tableStringPool); public abstract void merge(TableEntry tableEntry); @Override diff --git a/src/main/java/com/reandroid/arsc/value/ValueHeader.java b/src/main/java/com/reandroid/arsc/value/ValueHeader.java index 4e766cf..6f34ef2 100644 --- a/src/main/java/com/reandroid/arsc/value/ValueHeader.java +++ b/src/main/java/com/reandroid/arsc/value/ValueHeader.java @@ -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 { 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 { } 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 { int size = reader.readUnsignedShort(); setBytesLength(size, false); reader.readFully(getBytesInternal()); - linkStringReference(); } private void setName(String name){ if(name==null){ diff --git a/src/main/java/com/reandroid/arsc/value/ValueItem.java b/src/main/java/com/reandroid/arsc/value/ValueItem.java index 32fc29b..1a1cc26 100755 --- a/src/main/java/com/reandroid/arsc/value/ValueItem.java +++ b/src/main/java/com/reandroid/arsc/value/ValueItem.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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(); - if(tableString==null){ + 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();