    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) throws Pack200Exception {
    219        if (layout.startsWith("R")) { //$NON-NLS-1$
    220            // references
    221            if (layout.indexOf('N') != -1) {
    222                value--;
    223            }
    224            if (layout.startsWith("RU")) { //$NON-NLS-1$
    225                return pool.getValue(SegmentConstantPool.UTF_8, value);
    226            }
    227            if (layout.startsWith("RS")) { //$NON-NLS-1$
    228                return pool.getValue(SegmentConstantPool.SIGNATURE, value);
    229            }
    230        } else if (layout.startsWith("K")) { //$NON-NLS-1$
    231            final char type = layout.charAt(1);
    232            switch (type) {
    233            case 'S': // String
    234                return pool.getValue(SegmentConstantPool.CP_STRING, value);
    235            case 'I': // Int (or byte or short)
    236            case 'C': // Char
    237                return pool.getValue(SegmentConstantPool.CP_INT, value);
    238            case 'F': // Float
    239                return pool.getValue(SegmentConstantPool.CP_FLOAT, value);
    240            case 'J': // Long
    241                return pool.getValue(SegmentConstantPool.CP_LONG, value);
    242            case 'D': // Double
    243                return pool.getValue(SegmentConstantPool.CP_DOUBLE, value);
    244            }
    245        }
    246        throw new Pack200Exception("Unknown layout encoding: " + layout);
    247    }
    248
    249    private final int context;
    250
    251    private final int index;
    252
    253    private final String layout;
    254
    255    private long mask;
    256
    257    private final String name;
    258    private final boolean isDefault;
    259    private int backwardsCallCount;
    260
    261    /**
    262     * Constructs a default AttributeLayout (equivalent to {@code new AttributeLayout(name, context, layout, index, true);})
    263     *
    264     * @param name    TODO
    265     * @param context TODO
    266     * @param layout  TODO
    267     * @param index   TODO
    268     * @throws Pack200Exception Attribute context out of range.
    269     * @throws Pack200Exception Cannot have a null layout.
    270     * @throws Pack200Exception Cannot have an unnamed layout.
    271     */
    272    public AttributeLayout(final String name, final int context, final String layout, final int index) throws Pack200Exception {
    273        this(name, context, layout, index, true);
    274    }
    275
    276    public AttributeLayout(final String name, final int context, final String layout, final int index, final boolean isDefault) throws Pack200Exception {
    277        this.index = index;
    278        this.context = context;
    279        if (index >= 0) {
    280            this.mask = 1L << index;
    281        } else {
    282            this.mask = 0;
    283        }
    284        if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD && context != CONTEXT_METHOD) {
    285            throw new Pack200Exception("Attribute context out of range: " + context);
    286        }
    287        if (layout == null) {
    288            throw new Pack200Exception("Cannot have a null layout");
    289        }
    290        if (name == null || name.length() == 0) {
    291            throw new Pack200Exception("Cannot have an unnamed layout");
    292        }
    293        this.name = name;
    294        this.layout = layout;
    295        this.isDefault = isDefault;
    296    }
    297
    298    public Codec getCodec() {
    299        if (layout.indexOf('O') >= 0) {
    300            return Codec.BRANCH5;
    301        }
    302        if (layout.indexOf('P') >= 0) {
    303            return Codec.BCI5;
    304        }
    305        if (layout.indexOf('S') >= 0 && layout.indexOf("KS") < 0 //$NON-NLS-1$
    306                && layout.indexOf("RS") < 0) { //$NON-NLS-1$
    307            return Codec.SIGNED5;
    308        }
    309        if (layout.indexOf('B') >= 0) {
    310            return Codec.BYTE1;
    311        }
    312        return Codec.UNSIGNED5;
    313    }
    314
    315    public int getContext() {
    316        return context;
    317    }
    318
    319    public int getIndex() {
    320        return index;
    321    }
    322
    323    public String getLayout() {
    324        return layout;
    325    }
    326
    327    public String getName() {
    328        return name;
    329    }
    330
    331    public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception {
    332        return getValue(layout, value, pool);
    333    }
    334
    335    public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) throws Pack200Exception {
    336        // TODO This really needs to be better tested, esp. the different types
    337        // TODO This should have the ability to deal with RUN stuff too, and
    338        // unions
    339        if (!layout.startsWith("KQ")) {
    340            return getValue(layout, value, pool);
    341        }
    342        if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$
    343            return getValue("KS", value, pool);
    344        }
    345        return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$
    346                pool);
    347    }
    348
    349    @Override
    350    public int hashCode() {
    351        final int PRIME = 31;
    352        int r = 1;
    353        if (name != null) {
    354            r = r * PRIME + name.hashCode();
    355        }
    356        if (layout != null) {
    357            r = r * PRIME + layout.hashCode();
    358        }
    359        r = r * PRIME + index;
    360        r = r * PRIME + context;
    361        return r;
    362    }
    363
    364    public boolean isDefaultLayout() {
    365        return isDefault;
    366    }
    367
    368    /*
    369     * (non-Javadoc)
    370     *
    371     * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long)
    372     */
    373    @Override
    374    public boolean matches(final long value) {
    375        return (value & mask) != 0;
    376    }
    377
    378    public int numBackwardsCallables() {
    379        if ("*".equals(layout)) {
    380            return 1;
    381        }
    382        return backwardsCallCount;
    383    }
    384
    385    public void setBackwardsCallCount(final int backwardsCallCount) {
    386        this.backwardsCallCount = backwardsCallCount;
    387    }
    388
    389    @Override
    390    public String toString() {
    391        return contextNames[context] + ": " + name;
    392    }
    393
    394}