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

com.reandroid.common.ReferenceResolver Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
/*
 *  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.common;

import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.model.ResourceEntry;
import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.ResConfig;
import com.reandroid.arsc.value.ResValue;
import com.reandroid.arsc.value.ValueType;

import java.util.*;
import java.util.function.Predicate;

public class ReferenceResolver{
    private final TableBlock entryStore;
    private final List results;
    private final Set resolvedIds;
    private int limit;
    public ReferenceResolver(TableBlock entryStore){
        this.entryStore = entryStore;
        this.results = new ArrayList<>();
        this.resolvedIds = new HashSet<>();
        this.limit = -1;
    }
    public Entry resolve(int referenceId){
        return resolve(referenceId, null);
    }
    public synchronized Entry resolve(int referenceId, Predicate filter){
        resolveReference(referenceId, filter);
        List results = new ArrayList<>(this.results);
        reset();
        if(results.size() > 0){
            return results.get(0);
        }
        return null;
    }

    public List resolveWithConfig(int referenceId, ResConfig resConfig){
        ConfigFilter configFilter = new ConfigFilter(resConfig);
        List results = resolveAll(referenceId, configFilter);
        results.sort(configFilter);
        return results;
    }
    public List resolveAll(int referenceId){
        return resolveAll(referenceId, (Predicate)null);
    }
    public synchronized List resolveAll(int referenceId, Predicate filter){
        resolveReference(referenceId, filter);
        List results = new ArrayList<>(this.results);
        reset();
        return results;
    }
    private void resolveReference(int referenceId, Predicate filter){
        if(referenceId == 0 || isFinished() || this.resolvedIds.contains(referenceId)){
            return;
        }
        this.resolvedIds.add(referenceId);
        List entryList = listNonNullEntries(referenceId);
        List results = this.results;
        for(Entry entry:entryList){
            if(isFinished()){
                return;
            }
            if(results.contains(entry)){
                continue;
            }
            if(entry.isComplex()){
                addResult(filter, entry);
                continue;
            }
            ResValue resValue = entry.getResValue();
            if(resValue.getValueType() != ValueType.REFERENCE){
                addResult(filter, entry);
                continue;
            }
            resolveReference(resValue.getData(), filter);
        }
    }
    private void reset(){
        this.results.clear();
        this.resolvedIds.clear();
        this.limit = -1;
    }
    private boolean isFinished(){
        return this.limit >= this.results.size();
    }
    private void addResult(Predicate filter, Entry entry){
        if(filter == null || filter.test(entry)){
            this.results.add(entry);
        }
    }
    private List listNonNullEntries(int resourceId){
        List results = new ArrayList<>();
        ResourceEntry resourceEntry = this.entryStore.getResource(resourceId);
        if(resourceEntry == null){
            return results;
        }
        Iterator itr = resourceEntry.iterator(true);
        while (itr.hasNext()){
            results.add(itr.next());
        }
        return results;
    }

    public static class ConfigFilter implements Predicate, Comparator{
        private final ResConfig config;
        public ConfigFilter(ResConfig config){
            this.config = config;
        }
        @Override
        public boolean test(Entry entry) {
            ResConfig resConfig = entry.getResConfig();
            if(resConfig == null){
                return false;
            }
            return resConfig.isEqualOrMoreSpecificThan(this.config);
        }
        @Override
        public int compare(Entry entry1, Entry entry2) {
            ResConfig config1 = entry1.getResConfig();
            ResConfig config2 = entry2.getResConfig();
            if (config.equals(config1)){
                return -1;
            }
            if(config.equals(config2)){
                return 1;
            }
            return 0;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy