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

com.reandroid.dex.ins.InsSparseSwitchData 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.dex.ins;

import com.reandroid.arsc.base.Creator;
import com.reandroid.arsc.item.*;
import com.reandroid.common.ArraySupplier;
import com.reandroid.dex.base.CountedList;
import com.reandroid.dex.smali.SmaliDirective;
import com.reandroid.dex.smali.model.SmaliInstruction;
import com.reandroid.dex.smali.model.SmaliPayloadSparseSwitch;
import com.reandroid.dex.smali.model.SmaliSet;
import com.reandroid.dex.smali.model.SmaliSparseSwitchEntry;
import com.reandroid.utils.CompareUtil;
import com.reandroid.utils.ObjectsUtil;
import com.reandroid.utils.collection.ArraySupplierIterator;
import com.reandroid.dex.smali.SmaliWriter;
import com.reandroid.utils.HexUtil;

import java.io.IOException;
import java.util.Comparator;
import java.util.Iterator;

public class InsSparseSwitchData extends InsSwitchPayload implements
        ArraySupplier {

    private final ShortItem elementCount;
    final CountedList elements;
    final CountedList keys;

    boolean mSortRequired;

    public InsSparseSwitchData() {
        super(3, Opcode.SPARSE_SWITCH_PAYLOAD);
        this.elementCount = new ShortItem();

        Creator creator = new Creator() {
            @Override
            public IntegerItem[] newArrayInstance(int length) {
                return new IntegerItem[length];
            }
            @Override
            public IntegerItem newInstance() {
                return new IntegerItem();
            }
        };
        Creator entryKeyCreator = new Creator() {
            @Override
            public EntryKey[] newArrayInstance(int length) {
                return new EntryKey[length];
            }
            @Override
            public EntryKey newInstance() {
                return new EntryKey();
            }
        };

        this.elements = new CountedList<>(elementCount, creator);
        this.keys = new CountedList<>(elementCount, entryKeyCreator);

        addChild(1, elementCount);
        addChild(2, elements);
        addChild(3, keys);
    }

    @Override
    public Iterator iterator() {
        return ObjectsUtil.cast(getLabels());
    }
    public SparseSwitchEntry newEntry() {
        int index = getCount();
        setCount(index + 1);
        return get(index);
    }
    @Override
    public SparseSwitchEntry get(int i){
        if(i < 0 || i >= getCount()){
            return null;
        }
        return new SparseSwitchEntry(this, elements.get(i), keys.get(i));
    }
    @Override
    public int getCount(){
        return elements.size();
    }
    public void setCount(int count){
        int previous = getCount();
        boolean linked = false;
        InsBlockList insBlockList = getInsBlockList();
        if(count != previous) {
            if(insBlockList != null) {
                linked = insBlockList.isLinked();
                insBlockList.link();
            }
        }
        elements.setSize(count);
        keys.setSize(count);
        elementCount.set(count);
        if(insBlockList != null && !linked) {
            insBlockList.unlink();
        }
    }
    public void sort() {
        if(!mSortRequired) {
            return;
        }
        this.mSortRequired = false;
        Comparator comparator = (item1, item2) -> CompareUtil.compare(item1.get(), item2.get());
        if(!elements.needsSort(comparator)) {
            return;
        }
        this.elements.sort(comparator, keys);
    }
    @Override
    public Iterator getLabels() {
        return new ArraySupplierIterator<>(this);
    }

    public int getBaseAddress(){
        InsSparseSwitch sparseSwitch = getSwitch();
        if(sparseSwitch == null){
            return 0;
        }
        return sparseSwitch.getAddress();
    }

    @Override
    public Opcode getSwitchOpcode() {
        return Opcode.SPARSE_SWITCH;
    }
    @Override
    public InsSparseSwitch getSwitch() {
        return (InsSparseSwitch) super.getSwitch();
    }
    @Override
    protected void onPreRefresh() {
        sort();
        super.onPreRefresh();
    }
    void fromPackedSwitchData(PackedSwitchDataList packedSwitchDataList) {
        int length = packedSwitchDataList.size();
        setCount(length);
        for(int i = 0; i < length; i++) {
            get(i).fromPackedSwitch(packedSwitchDataList.get(i));
        }
    }
    @Override
    public void merge(Ins ins){
        InsSparseSwitchData switchData = (InsSparseSwitchData) ins;
        int size = switchData.getCount();
        this.setCount(size);
        for(int i = 0; i < size; i++){
            get(i).merge(switchData.get(i));
        }
    }

    @Override
    public void fromSmali(SmaliInstruction smaliInstruction) throws IOException {
        validateOpcode(smaliInstruction);
        SmaliPayloadSparseSwitch smaliPayloadSparseSwitch = (SmaliPayloadSparseSwitch) smaliInstruction;
        SmaliSet entries = smaliPayloadSparseSwitch.getEntries();
        int count = entries.size();
        this.setCount(count);
        for(int i = 0; i < count; i++) {
            SmaliSparseSwitchEntry smaliEntry = entries.get(i);
            SparseSwitchEntry data = get(i);
            data.fromSmali(smaliEntry);
        }
        mSortRequired = true;
    }

    @Override
    public void appendCode(SmaliWriter writer) throws IOException {
        getSmaliDirective().append(writer);
        int size = getCount();
        writer.indentPlus();
        for(int i = 0; i < size; i++){
            get(i).append(writer);
        }
        writer.indentMinus();
        writer.newLine();
        getSmaliDirective().appendEnd(writer);
    }

    @Override
    public SmaliDirective getSmaliDirective() {
        return SmaliDirective.SPARSE_SWITCH;
    }

    static class EntryKey extends IntegerItem {
        private Ins targetIns;

        EntryKey() {
            super();
        }

        public Ins getTargetIns() {
            return targetIns;
        }
        public void setTargetIns(Ins targetIns) {
            this.targetIns = targetIns;
        }
    }
    public static class SparseSwitchEntry implements InsSwitchPayload.SwitchEntry {

        private final InsSparseSwitchData payload;
        private final IntegerReference element;
        private final EntryKey key;

        public SparseSwitchEntry(InsSparseSwitchData payload, IntegerReference element, EntryKey key){
            this.payload = payload;
            this.element = element;
            this.key = key;
        }

        @Override
        public InsSparseSwitchData getPayload() {
            return payload;
        }
        @Override
        public int get(){
            return element.get();
        }
        @Override
        public void set(int value){
            if(value != element.get()) {
                element.set(value);
                this.payload.mSortRequired = true;
            }
        }
        @Override
        public Ins getTargetIns() {
            Ins targetIns = this.key.getTargetIns();
            if(targetIns == null) {
                setTargetIns(findTargetIns());
                targetIns = this.key.getTargetIns();
            }
            return targetIns;
        }
        @Override
        public void setTargetIns(Ins targetIns) {
            Ins ins = key.getTargetIns();
            if(targetIns != ins) {
                key.setTargetIns(targetIns);
                if(targetIns != null) {
                    targetIns.addExtraLine(this);
                }
            }
        }

        public int getKey(){
            return key.get();
        }
        public void setKey(int value){
            key.set(value);
        }

        @Override
        public int getSortOrder() {
            return ExtraLine.ORDER_INSTRUCTION_LABEL;
        }
        @Override
        public int getAddress() {
            return payload.getAddress();
        }
        @Override
        public int getTargetAddress() {
            return getKey() + payload.getBaseAddress();
        }
        @Override
        public void setTargetAddress(int targetAddress){
            setKey(targetAddress - payload.getBaseAddress());
        }
        @Override
        public String getLabelName() {
            return HexUtil.toHex(":sswitch_", getTargetAddress(), 1);
        }
        @Override
        public void append(SmaliWriter writer) throws IOException {
            writer.newLine();
            int value = get();
            writer.appendHex(value);
            writer.append(" -> ");
            writer.appendLabelName(getLabelName());
            writer.appendResourceIdComment(value);
        }

        @Override
        public void appendExtra(SmaliWriter writer) throws IOException {
            writer.appendLabelName(getLabelName());
            writer.appendComment(HexUtil.toSignedHex(get()));
        }

        public void fromPackedSwitch(PackedSwitchDataList.PackedSwitchEntry packedSwitchEntry) {
            this.set(packedSwitchEntry.get());
            Ins ins = packedSwitchEntry.getTargetIns();
            this.setTargetAddress(ins.getAddress());
            this.setTargetIns(ins);
            ins.addExtraLine(this);
        }
        public void merge(SparseSwitchEntry data) {
            set(data.get());
            setKey(data.getKey());
        }
        public void fromSmali(SmaliSparseSwitchEntry smaliEntry) throws IOException{
            set(smaliEntry.getValue());
            setKey(smaliEntry.getRelativeOffset());
        }
        @Override
        public int hashCode() {
            return ObjectsUtil.hash(payload, element);
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
            SparseSwitchEntry data = (SparseSwitchEntry) obj;
            return element == data.element && payload == data.payload;
        }
        @Override
        public String toString() {
            return HexUtil.toHex8(get()) + " -> " + getKey();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy