    001/*
    002 *  Licensed to the Apache Software Foundation (ASF) under one or more
    003 *  contributor license agreements.  See the NOTICE file distributed with
    004 *  this work for additional information regarding copyright ownership.
    005 *  The ASF licenses this file to You under the Apache License, Version 2.0
    006 *  (the "License"); you may not use this file except in compliance with
    007 *  the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.commons.compress.harmony.unpack200;
    018
    019import org.apache.commons.compress.harmony.pack200.Codec;
    020import org.apache.commons.compress.harmony.pack200.Pack200Exception;
    021import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
    022
    023/**
    024 * AttributeLayout defines a layout that describes how an attribute will be transmitted.
    025 */
    026public class AttributeLayout implements IMatcher {
    027
    028    /**
    029     * {@value}
    030     */
    031    public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$
    032
    033    /**
    034     * {@value}
    035     */
    036    public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$
    037
    038    /**
    039     * {@value}
    040     */
    041    public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$
    042
    043    /**
    044     * {@value}
    045     */
    046    public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$
    047
    048    /**
    049     * {@value}
    050     */
    051    public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$
    052
    053    /**
    054     * {@value}
    055     */
    056    public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$
    057
    058    /**
    059     * {@value}
    060     */
    061    public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$
    062
    063    /**
    064     * {@value}
    065     */
    066    public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$
    067
    068    /**
    069     * {@value}
    070     */
    071    public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$
    072
    073    /**
    074     * {@value}
    075     */
    076    public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$
    077
    078    /**
    079     * {@value}
    080     */
    081    public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$
    082
    083    /**
    084     * {@value}
    085     */
    086    public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$
    087
    088    /**
    089     * {@value}
    090     */
    091    public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$
    092
    093    /**
    094     * {@value}
    095     */
    096    public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$
    097
    098    /**
    099     * {@value}
    100     */
    101    public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$
    102
    103    /**
    104     * {@value}
    105     */
    106    public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$
    107
    108    /**
    109     * {@value}
    110     */
    111    public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$
    112
    113    /**
    114     * {@value}
    115     */
    116    public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$
    117
    118    /**
    119     * {@value}
    120     */
    121    public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$
    122
    123    /**
    124     * {@value}
    125     */
    126    public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$
    127
    128    /**
    129     * {@value}
    130     */
    131
    132    /**
    133     * {@value}
    134     */
    135    public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$
    136
    137    /**
    138     * {@value}
    139     */
    140    public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$
    141
    142    /**
    143     * {@value}
    144     */
    145    public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$
    146
    147    /**
    148     * {@value}
    149     */
    150    public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$
    151
    152    /**
    153     * {@value}
    154     */
    155    public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$
    156
    157    /**
    158     * {@value}
    159     */
    160    public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$
    161
    162    /**
    163     * {@value}
    164     */
    165    public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$
    166
    167    /**
    168     * {@value}
    169     */
    170    public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$
    171
    172    /**
    173     * {@value}
    174     */
    175    public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$
    176
    177    /**
    178     * {@value}
    179     */
    180    public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$
    181
    182    /**
    183     * {@value}
    184     */
    185    public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$
    186
    187    /**
    188     * {@value}
    189     */
    190    public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$
    191
    192    /**
    193     * {@value}
    194     */
    195    public static final int CONTEXT_CLASS = 0;
    196
    197    /**
    198     * {@value}
    199     */
    200    public static final int CONTEXT_CODE = 3;
    201
    202    /**
    203     * {@value}
    204     */
    205    public static final int CONTEXT_FIELD = 1;
    206
    207    /**
    208     * {@value}
    209     */
    210    public static final int CONTEXT_METHOD = 2;
    211
    212    /**
    213     * Context names.
    214     */
    215    public static final String[] contextNames = {"Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    216        "Code",}; //$NON-NLS-1$
    217
    218    private static ClassFileEntry getValue(final String layout, long value, final SegmentConstantPool pool)
    219        throws Pack200Exception {
    220        if (layout.startsWith("R")) { //$NON-NLS-1$
    221            // references
    222            if (layout.indexOf('N') != -1) {
    223                value--;
    224            }
    225            if (layout.startsWith("RU")) { //$NON-NLS-1$
    226                return pool.getValue(SegmentConstantPool.UTF_8, value);
    227            }
    228            if (layout.startsWith("RS")) { //$NON-NLS-1$
    229                return pool.getValue(SegmentConstantPool.SIGNATURE, value);
    230            }
    231        } else if (layout.startsWith("K")) { //$NON-NLS-1$
    232            final char type = layout.charAt(1);
    233            switch (type) {
    234            case 'S': // String
    235                return pool.getValue(SegmentConstantPool.CP_STRING, value);
    236            case 'I': // Int (or byte or short)
    237            case 'C': // Char
    238                return pool.getValue(SegmentConstantPool.CP_INT, value);
    239            case 'F': // Float
    240                return pool.getValue(SegmentConstantPool.CP_FLOAT, value);
    241            case 'J': // Long
    242                return pool.getValue(SegmentConstantPool.CP_LONG, value);
    243            case 'D': // Double
    244                return pool.getValue(SegmentConstantPool.CP_DOUBLE, value);
    245            }
    246        }
    247        throw new Pack200Exception("Unknown layout encoding: " + layout);
    248    }
    249
    250    private final int context;
    251
    252    private final int index;
    253
    254    private final String layout;
    255
    256    private long mask;
    257
    258    private final String name;
    259    private final boolean isDefault;
    260    private int backwardsCallCount;
    261
    262    /**
    263     * Constructs a default AttributeLayout (equivalent to
    264     * {@code new AttributeLayout(name, context, layout, index, true);})
    265     *
    266     * @param name TODO
    267     * @param context TODO
    268     * @param layout TODO
    269     * @param index TODO
    270     * @throws Pack200Exception Attribute context out of range.
    271     * @throws Pack200Exception Cannot have a null layout.
    272     * @throws Pack200Exception Cannot have an unnamed layout.
    273     */
    274    public AttributeLayout(final String name, final int context, final String layout, final int index)
    275        throws Pack200Exception {
    276        this(name, context, layout, index, true);
    277    }
    278
    279    public AttributeLayout(final String name, final int context, final String layout, final int index,
    280        final boolean isDefault) throws Pack200Exception {
    281        this.index = index;
    282        this.context = context;
    283        if (index >= 0) {
    284            this.mask = 1L << index;
    285        } else {
    286            this.mask = 0;
    287        }
    288        if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD
    289            && context != CONTEXT_METHOD) {
    290            throw new Pack200Exception("Attribute context out of range: " + context);
    291        }
    292        if (layout == null) {
    293            throw new Pack200Exception("Cannot have a null layout");
    294        }
    295        if (name == null || name.length() == 0) {
    296            throw new Pack200Exception("Cannot have an unnamed layout");
    297        }
    298        this.name = name;
    299        this.layout = layout;
    300        this.isDefault = isDefault;
    301    }
    302
    303    public Codec getCodec() {
    304        if (layout.indexOf('O') >= 0) {
    305            return Codec.BRANCH5;
    306        }
    307        if (layout.indexOf('P') >= 0) {
    308            return Codec.BCI5;
    309        }
    310        if (layout.indexOf('S') >= 0 && layout.indexOf("KS") < 0 //$NON-NLS-1$
    311            && layout.indexOf("RS") < 0) { //$NON-NLS-1$
    312            return Codec.SIGNED5;
    313        }
    314        if (layout.indexOf('B') >= 0) {
    315            return Codec.BYTE1;
    316        }
    317        return Codec.UNSIGNED5;
    318    }
    319
    320    public int getContext() {
    321        return context;
    322    }
    323
    324    public int getIndex() {
    325        return index;
    326    }
    327
    328    public String getLayout() {
    329        return layout;
    330    }
    331
    332    public String getName() {
    333        return name;
    334    }
    335
    336    public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception {
    337        return getValue(layout, value, pool);
    338    }
    339
    340    public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool)
    341        throws Pack200Exception {
    342        // TODO This really needs to be better tested, esp. the different types
    343        // TODO This should have the ability to deal with RUN stuff too, and
    344        // unions
    345        if (!layout.startsWith("KQ")) {
    346            return getValue(layout, value, pool);
    347        }
    348        if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$
    349            return getValue("KS", value, pool);
    350        }
    351        return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$
    352            pool);
    353    }
    354
    355    @Override
    356    public int hashCode() {
    357        final int PRIME = 31;
    358        int r = 1;
    359        if (name != null) {
    360            r = r * PRIME + name.hashCode();
    361        }
    362        if (layout != null) {
    363            r = r * PRIME + layout.hashCode();
    364        }
    365        r = r * PRIME + index;
    366        r = r * PRIME + context;
    367        return r;
    368    }
    369
    370    public boolean isDefaultLayout() {
    371        return isDefault;
    372    }
    373
    374    /*
    375     * (non-Javadoc)
    376     *
    377     * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long)
    378     */
    379    @Override
    380    public boolean matches(final long value) {
    381        return (value & mask) != 0;
    382    }
    383
    384    public int numBackwardsCallables() {
    385        if ("*".equals(layout)) {
    386            return 1;
    387        }
    388        return backwardsCallCount;
    389    }
    390
    391    public void setBackwardsCallCount(final int backwardsCallCount) {
    392        this.backwardsCallCount = backwardsCallCount;
    393    }
    394
    395    @Override
    396    public String toString() {
    397        return contextNames[context] + ": " + name;
    398    }
    399
    400}