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

org.apache.commons.compress.harmony.unpack200.IcBands Maven / Gradle / Ivy

Go to download

Apache Commons Compress defines an API for working with compression and archive formats. These include bzip2, gzip, pack200, LZMA, XZ, Snappy, traditional Unix Compress, DEFLATE, DEFLATE64, LZ4, Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.

There is a newer version: 1.27.1
Show newest version
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 org.apache.commons.compress.harmony.unpack200;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.compress.harmony.pack200.Codec;
import org.apache.commons.compress.harmony.pack200.Pack200Exception;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
import org.apache.commons.compress.harmony.unpack200.bytecode.ClassConstantPool;
import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantPoolEntry;

/**
 * Inner Class Bands
 */
public class IcBands extends BandSet {

    private IcTuple[] icAll;

    private final String[] cpUTF8;

    private final String[] cpClass;

    private Map thisClassToTuple;
    private Map> outerClassToTuples;

    /**
     * @param segment TODO
     */
    public IcBands(final Segment segment) {
        super(segment);
        this.cpClass = segment.getCpBands().getCpClass();
        this.cpUTF8 = segment.getCpBands().getCpUTF8();
    }

    public IcTuple[] getIcTuples() {
        return icAll;
    }

    /**
     * Answer the relevant IcTuples for the specified className and class constant pool.
     *
     * @param className String name of the class X for ic_relevant(X)
     * @param cp        ClassConstantPool used to generate ic_relevant(X)
     * @return array of IcTuple
     */
    public IcTuple[] getRelevantIcTuples(final String className, final ClassConstantPool cp) {
        final Set relevantTuplesContains = new HashSet<>();
        final List relevantTuples = new ArrayList<>();

        final List relevantCandidates = outerClassToTuples.get(className);
        if (relevantCandidates != null) {
            for (int index = 0; index < relevantCandidates.size(); index++) {
                final IcTuple tuple = relevantCandidates.get(index);
                relevantTuplesContains.add(tuple);
                relevantTuples.add(tuple);
            }
        }

        final List entries = cp.entries();

        // For every class constant in both ic_this_class and cp,
        // add it to ic_relevant. Repeat until no more
        // changes to ic_relevant.

        for (int eIndex = 0; eIndex < entries.size(); eIndex++) {
            final ConstantPoolEntry entry = (ConstantPoolEntry) entries.get(eIndex);
            if (entry instanceof CPClass) {
                final CPClass clazz = (CPClass) entry;
                final IcTuple relevant = thisClassToTuple.get(clazz.name);
                if (relevant != null && relevantTuplesContains.add(relevant)) {
                    relevantTuples.add(relevant);
                }
            }
        }

        // Not part of spec: fix up by adding to relevantTuples the parents
        // of inner classes which are themselves inner classes.
        // i.e., I think that if Foo$Bar$Baz gets added, Foo$Bar needs to be
        // added
        // as well.

        final List tuplesToScan = new ArrayList<>(relevantTuples);
        final List tuplesToAdd = new ArrayList<>();

        while (tuplesToScan.size() > 0) {

            tuplesToAdd.clear();
            for (int index = 0; index < tuplesToScan.size(); index++) {
                final IcTuple aRelevantTuple = tuplesToScan.get(index);
                final IcTuple relevant = thisClassToTuple.get(aRelevantTuple.outerClassString());
                if (relevant != null && !aRelevantTuple.outerIsAnonymous()) {
                    tuplesToAdd.add(relevant);
                }
            }

            tuplesToScan.clear();
            for (int index = 0; index < tuplesToAdd.size(); index++) {
                final IcTuple tuple = tuplesToAdd.get(index);
                if (relevantTuplesContains.add(tuple)) {
                    relevantTuples.add(tuple);
                    tuplesToScan.add(tuple);
                }
            }

        }

        // End not part of the spec. Ugh.

        // Now order the result as a subsequence of ic_all
        relevantTuples.sort((arg0, arg1) -> {
            final int index1 = arg0.getTupleIndex();
            final Integer index2 = Integer.valueOf(arg1.getTupleIndex());
            return Integer.compare(index1, index2);
        });

        return relevantTuples.toArray(IcTuple.EMPTY_ARRAY);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
     */
    @Override
    public void read(final InputStream in) throws IOException, Pack200Exception {
        // Read IC bands
        final int innerClassCount = header.getInnerClassCount();
        final int[] icThisClassInts = decodeBandInt("ic_this_class", in, Codec.UDELTA5, innerClassCount);
        final String[] icThisClass = getReferences(icThisClassInts, cpClass);
        final int[] icFlags = decodeBandInt("ic_flags", in, Codec.UNSIGNED5, innerClassCount);
        final int outerClasses = SegmentUtils.countBit16(icFlags);
        final int[] icOuterClassInts = decodeBandInt("ic_outer_class", in, Codec.DELTA5, outerClasses);
        final String[] icOuterClass = new String[outerClasses];
        for (int i = 0; i < icOuterClass.length; i++) {
            if (icOuterClassInts[i] == 0) {
                icOuterClass[i] = null;
            } else {
                icOuterClass[i] = cpClass[icOuterClassInts[i] - 1];
            }
        }
        final int[] icNameInts = decodeBandInt("ic_name", in, Codec.DELTA5, outerClasses);
        final String[] icName = new String[outerClasses];
        for (int i = 0; i < icName.length; i++) {
            if (icNameInts[i] == 0) {
                icName[i] = null;
            } else {
                icName[i] = cpUTF8[icNameInts[i] - 1];
            }
        }

        // Construct IC tuples
        icAll = new IcTuple[icThisClass.length];
        int index = 0;
        for (int i = 0; i < icThisClass.length; i++) {
            final String icTupleC = icThisClass[i];
            final int icTupleF = icFlags[i];
            String icTupleC2 = null;
            String icTupleN = null;
            final int cIndex = icThisClassInts[i];
            int c2Index = -1;
            int nIndex = -1;
            if ((icFlags[i] & 1 << 16) != 0) {
                icTupleC2 = icOuterClass[index];
                icTupleN = icName[index];
                c2Index = icOuterClassInts[index] - 1;
                nIndex = icNameInts[index] - 1;
                index++;
            }
            icAll[i] = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, cIndex, c2Index, nIndex, i);
        }
    }

    @Override
    public void unpack() throws IOException, Pack200Exception {
        final IcTuple[] allTuples = getIcTuples();
        thisClassToTuple = new HashMap<>(allTuples.length);
        outerClassToTuples = new HashMap<>(allTuples.length);
        for (final IcTuple tuple : allTuples) {

            // generate mapping thisClassString -> IcTuple
            // presumably this relation is 1:1
            //
            final Object result = thisClassToTuple.put(tuple.thisClassString(), tuple);
            if (result != null) {
                throw new Error("Collision detected in  mapping. " + "There are at least two inner clases with the same name.");
            }

            // generate mapping outerClassString -> IcTuple
            // this relation is 1:M

            // If it's not anon and the outer is not anon, it could be relevant
            if (!tuple.isAnonymous() && !tuple.outerIsAnonymous() || tuple.nestedExplicitFlagSet()) {

                // add tuple to corresponding bucket
                final String key = tuple.outerClassString();
                outerClassToTuples.computeIfAbsent(key, k -> new ArrayList<>()).add(tuple);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy