All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reandroid.arsc.chunk.xml.ResXmlStartElement Maven / Gradle / Ivy

/*
 *  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.chunk.ChunkType;
import com.reandroid.arsc.array.ResXmlAttributeArray;
import com.reandroid.arsc.item.ShortItem;

import java.util.Collection;

public class ResXmlStartElement extends BaseXmlChunk {
    private final ShortItem mAttributeStart;
    private final ShortItem mAttributeUnitSize;
    private final ShortItem mAttributeCount;
    private final ShortItem mIdAttributePosition;
    private final ShortItem mClassAttributePosition;
    private final ShortItem mStyleAttributePosition;
    private final ResXmlAttributeArray mAttributeArray;
    private ResXmlEndElement mResXmlEndElement;
    public ResXmlStartElement() {
        super(ChunkType.XML_START_ELEMENT, 7);
        mAttributeStart = new ShortItem(ATTRIBUTES_DEFAULT_START);
        mAttributeUnitSize = new ShortItem(ATTRIBUTES_UNIT_SIZE);
        mAttributeCount = new ShortItem();
        mIdAttributePosition = new ShortItem();
        mClassAttributePosition = new ShortItem();
        mStyleAttributePosition = new ShortItem();
        mAttributeArray = new ResXmlAttributeArray(getHeaderBlock(),
                mAttributeStart,
                mAttributeCount,
                mAttributeUnitSize);
        addChild(mAttributeStart);
        addChild(mAttributeUnitSize);
        addChild(mAttributeCount);
        addChild(mIdAttributePosition);
        addChild(mClassAttributePosition);
        addChild(mStyleAttributePosition);
        addChild(mAttributeArray);
    }

    public int removeUndefinedAttributes(){
        return getResXmlAttributeArray().removeUndefinedAttributes();
    }
    public ResXmlAttribute getIdAttribute(){
        return getResXmlAttributeArray().get(mIdAttributePosition.unsignedInt()-1);
    }
    public ResXmlAttribute getClassAttribute(){
        return getResXmlAttributeArray().get(mClassAttributePosition.unsignedInt()-1);
    }
    public ResXmlAttribute getStyleAttribute(){
        return getResXmlAttributeArray().get(mStyleAttributePosition.unsignedInt()-1);
    }
    void setAttributesUnitSize(int size){
        mAttributeArray.setAttributesUnitSize(size);
    }
    public ResXmlAttribute newAttribute(){
        ResXmlAttributeArray attributeArray = getResXmlAttributeArray();
        return attributeArray.createNext();
    }
    @Override
    void linkStringReferences(){
        super.linkStringReferences();
        ResXmlEndElement end = getResXmlEndElement();
        if(end != null){
            end.linkStringReferences();
        }
        linkNamespace();
    }
    @Override
    void onRemoved(){
        super.onRemoved();
        unlinkNamespace();
        ResXmlEndElement end = getResXmlEndElement();
        if(end != null){
            end.onRemoved();
        }
        for(ResXmlAttribute attr:listResXmlAttributes()){
            attr.onRemoved();
        }
    }
    @Override
    protected void onPreRefreshRefresh(){
        sortAttributes();
    }
    void unlinkNamespace(){
        ResXmlStartNamespace namespace = getResXmlStartNamespace();
        if(namespace != null){
            namespace.removeElementReference(this);
        }
    }
    void linkNamespace(){
        ResXmlStartNamespace namespace = getResXmlStartNamespace();
        if(namespace != null){
            namespace.addElementReference(this);
        }
    }
    private void sortAttributes(){
        ResXmlAttributeArray array = getResXmlAttributeArray();

        ResXmlAttribute idAttribute=array.get(mIdAttributePosition.get()-1);
        ResXmlAttribute classAttribute=array.get(mClassAttributePosition.get()-1);
        ResXmlAttribute styleAttribute=array.get(mStyleAttributePosition.get()-1);

        array.sortAttributes();
        if(idAttribute!=null){
            mIdAttributePosition.set((short) (idAttribute.getIndex()+1));
        }
        if(classAttribute!=null){
            mClassAttributePosition.set((short) (classAttribute.getIndex()+1));
            // In case obfuscation
            if(!ATTRIBUTE_NAME_CLASS.equals(classAttribute.getName())){
                classAttribute.setName(ATTRIBUTE_NAME_CLASS, 0);
            }
        }
        if(styleAttribute!=null){
            mStyleAttributePosition.set((short) (styleAttribute.getIndex()+1));
            // In case obfuscation
            if(!ATTRIBUTE_NAME_STYLE.equals(styleAttribute.getName())){
                styleAttribute.setName(ATTRIBUTE_NAME_STYLE, 0);
            }
        }
    }
    void calculatePositions(){
        ResXmlAttribute idAttribute=getAttribute(ATTRIBUTE_RESOURCE_ID_id);
        ResXmlAttribute classAttribute=getNoIdAttribute(ATTRIBUTE_NAME_CLASS);
        ResXmlAttribute styleAttribute=getNoIdAttribute(ATTRIBUTE_NAME_STYLE);

        if(idAttribute!=null){
            mIdAttributePosition.set((short) (idAttribute.getIndex()+1));
        }
        if(classAttribute!=null){
            mClassAttributePosition.set((short) (classAttribute.getIndex()+1));
        }
        if(styleAttribute!=null){
            mStyleAttributePosition.set((short) (styleAttribute.getIndex()+1));
        }
    }
    public ResXmlAttribute getAttribute(int resourceId){
        for(ResXmlAttribute attribute:listResXmlAttributes()){
            if(resourceId==attribute.getNameResourceID()){
                return attribute;
            }
        }
        return null;
    }
    private ResXmlAttribute getNoIdAttribute(String name){
        for(ResXmlAttribute attribute:listResXmlAttributes()){
            if(attribute.getNameResourceID()!=0){
                continue;
            }
            if(name.equals(attribute.getName())){
                return attribute;
            }
        }
        return null;
    }
    public ResXmlAttribute getAttribute(String uri, String name){
        if(name==null){
            return null;
        }
        for(ResXmlAttribute attribute:listResXmlAttributes()){
            if(attribute.equalsName(name)){
                if(uri != null){
                    if(uri.equals(attribute.getUri())){
                        return attribute;
                    }
                    continue;
                }
                return attribute;
            }
        }
        return null;
    }
    // Searches attribute with resource id = 0
    public ResXmlAttribute searchAttributeByName(String name){
        if(name == null){
            return null;
        }
        ResXmlAttribute withIdAttribute = null;
        for(ResXmlAttribute attribute:listResXmlAttributes()){
            if(attribute.equalsName(name)){
                if(attribute.getNameResourceID() != 0){
                    withIdAttribute = attribute;
                    continue;
                }
                return attribute;
            }
        }
        return withIdAttribute;
    }
    public ResXmlAttribute searchAttributeByResourceId(int resourceId){
        if(resourceId == 0){
            return null;
        }
        for(ResXmlAttribute attribute:listResXmlAttributes()){
            if(resourceId == attribute.getNameResourceID()){
                return attribute;
            }
        }
        return null;
    }
    public String getTagName(){
        return getTagName(true);
    }
    public String getTagName(boolean includePrefix){
        String name = getName();
        if(includePrefix){
            String prefix = getPrefix();
            if(prefix != null){
                name = prefix + ":" + name;
            }
        }
        return name;
    }
    public String getName(boolean includePrefix){
        String name = super.getName();
        if(includePrefix){
            String prefix = getPrefix();
            if(prefix != null){
                name = prefix + ":" + name;
            }
        }
        return name;
    }
    public void setName(String name){
        if(name == null){
            setStringReference(-1);
        }else {
            setString(name);
        }
        ResXmlEndElement endElement = getResXmlEndElement();
        if(endElement != null){
            endElement.setString(name);
        }
    }
    public Collection listResXmlAttributes(){
        return getResXmlAttributeArray().listItems();
    }
    public ResXmlAttributeArray getResXmlAttributeArray(){
        return mAttributeArray;
    }

    public String getUri(){
        ResXmlStartNamespace startNamespace = getResXmlStartNamespace();
        if(startNamespace != null){
            return startNamespace.getUri();
        }
        return null;
    }
    public String getPrefix(){
        ResXmlStartNamespace startNamespace = getResXmlStartNamespace();
        if(startNamespace != null){
            return startNamespace.getPrefix();
        }
        return null;
    }
    public void setTagNamespace(String uri, String prefix){
        unlinkNamespace();
        if(uri == null || prefix == null){
            setNamespaceReference(-1);
            return;
        }
        ResXmlElement parentElement = getParentResXmlElement();
        if(parentElement == null){
            return;
        }
        ResXmlNamespace ns = parentElement.getOrCreateNamespace(uri, prefix);
        setNamespaceReference(ns.getUriReference());
        linkNamespace();
    }
    private ResXmlStartNamespace getResXmlStartNamespace(){
        int uriRef = getNamespaceReference();
        if(uriRef < 0){
            return null;
        }
        ResXmlElement parentElement = getParentResXmlElement();
        if(parentElement != null){
            return parentElement.getStartNamespaceByUriRef(uriRef);
        }
        return null;
    }
    public void setResXmlEndElement(ResXmlEndElement element){
        mResXmlEndElement=element;
    }
    public ResXmlEndElement getResXmlEndElement(){
        return mResXmlEndElement;
    }

    @Override
    protected void onChunkRefreshed() {
        refreshAttributeStart();
        refreshAttributeCount();
    }
    private void refreshAttributeStart(){
        int start=countUpTo(mAttributeArray);
        start=start-getHeaderBlock().getHeaderSize();
        mAttributeStart.set((short)start);
    }
    private void refreshAttributeCount(){
        int count=mAttributeArray.childesCount();
        mAttributeCount.set((short)count);
    }

    @Override
    public String toString(){
        String txt=getTagName();
        if(txt==null){
            return super.toString();
        }
        StringBuilder builder=new StringBuilder();
        builder.append(txt);
        ResXmlAttribute[] allAttr=mAttributeArray.getChildes();
        if(allAttr!=null){
            for(int i=0;i10){
                    break;
                }
                builder.append(" ");
                builder.append(allAttr[i].toString());
            }
        }
        return builder.toString();
    }

    private static final short ATTRIBUTES_UNIT_SIZE=20;
    private static final short ATTRIBUTES_DEFAULT_START=20;
    /*
     * Find another way to mark an attribute is class, device actually relies on
     * value of mClassAttributePosition */
    private static final String ATTRIBUTE_NAME_CLASS="class";
    /*
     * Find another way to mark an attribute is style, device actually relies on
     * value of mStyleAttributePosition */
    private static final String ATTRIBUTE_NAME_STYLE="style";
    /*
     * Resource id value of attribute 'android:id'
     * instead of relying on hardcoded value, we should find another way to
     * mark an attribute is 'id' */
    private static final int ATTRIBUTE_RESOURCE_ID_id =0x010100d0;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy