    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.pack200;
    018
    019import org.objectweb.asm.Attribute;
    020import org.objectweb.asm.ClassReader;
    021import org.objectweb.asm.Label;
    022
    023/**
    024 * NewAttribute extends {@code Attribute} and manages unknown attributes encountered by ASM that have had a layout
    025 * definition given to pack200 (e.g. via one of the -C, -M, -F or -D command line options)
    026 */
    027public class NewAttribute extends Attribute {
    028
    029    /**
    030     * ErrorAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had an error
    031     * action specified to pack200 (e.g. via one of the -C, -M, -F or -D command line options such as
    032     * -Cattribute-name=error)
    033     */
    034    public static class ErrorAttribute extends NewAttribute {
    035
    036        public ErrorAttribute(final String type, final int context) {
    037            super(type, "", context);
    038        }
    039
    040        @Override
    041        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf,
    042            final int codeOff, final Label[] labels) {
    043            throw new Error("Attribute " + type + " was found");
    044        }
    045
    046    }
    047    /**
    048     * PassAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a pass
    049     * action specified to pack200 (e.g. via one of the -C, -M, -F or -D command line options such as
    050     * -Cattribute-name=pass)
    051     */
    052    public static class PassAttribute extends NewAttribute {
    053
    054        public PassAttribute(final String type, final int context) {
    055            super(type, "", context);
    056        }
    057
    058        @Override
    059        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf,
    060            final int codeOff, final Label[] labels) {
    061            throw new Segment.PassException();
    062        }
    063
    064    }
    065    /**
    066     * StripAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a strip
    067     * action specified to pack200 (e.g. via one of the -C, -M, -F or -D command line options such as
    068     * -Cattribute-name=strip)
    069     */
    070    public static class StripAttribute extends NewAttribute {
    071
    072        public StripAttribute(final String type, final int context) {
    073            super(type, "", context);
    074        }
    075
    076        @Override
    077        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf,
    078            final int codeOff, final Label[] labels) {
    079            // TODO Not sure if this works, can we really strip an attribute if we don't know the layout?
    080            return null;
    081        }
    082    }
    083    private boolean contextClass;
    084
    085    private boolean contextMethod;
    086    private boolean contextField;
    087    private boolean contextCode;
    088    private final String layout;
    089    private byte[] contents;
    090    private int codeOff;
    091
    092    private Label[] labels;
    093
    094    private ClassReader classReader;
    095
    096    private char[] buf;
    097
    098    public NewAttribute(final ClassReader classReader, final String type, final String layout, final byte[] contents,
    099        final char[] buf, final int codeOff, final Label[] labels) {
    100        super(type);
    101        this.classReader = classReader;
    102        this.contents = contents;
    103        this.layout = layout;
    104        this.codeOff = codeOff;
    105        this.labels = labels;
    106        this.buf = buf;
    107    }
    108
    109    public NewAttribute(final String type, final String layout, final int context) {
    110        super(type);
    111        this.layout = layout;
    112        addContext(context);
    113    }
    114
    115    public void addContext(final int context) {
    116        switch (context) {
    117        case AttributeDefinitionBands.CONTEXT_CLASS:
    118            contextClass = true;
    119            break;
    120        case AttributeDefinitionBands.CONTEXT_METHOD:
    121            contextMethod = true;
    122            break;
    123        case AttributeDefinitionBands.CONTEXT_FIELD:
    124            contextField = true;
    125            break;
    126        case AttributeDefinitionBands.CONTEXT_CODE:
    127            contextCode = true;
    128            break;
    129        }
    130    }
    131
    132    public byte[] getBytes() {
    133        return contents;
    134    }
    135
    136    public Label getLabel(final int index) {
    137        return labels[index];
    138    }
    139
    140    public String getLayout() {
    141        return layout;
    142    }
    143
    144    @Override
    145    public boolean isCodeAttribute() {
    146        return codeOff != -1;
    147    }
    148
    149    public boolean isContextClass() {
    150        return contextClass;
    151    }
    152
    153    public boolean isContextCode() {
    154        return contextCode;
    155    }
    156
    157    public boolean isContextField() {
    158        return contextField;
    159    }
    160
    161    public boolean isContextMethod() {
    162        return contextMethod;
    163    }
    164
    165    @Override
    166    public boolean isUnknown() {
    167        return false;
    168    }
    169
    170    public boolean isUnknown(final int context) {
    171        switch (context) {
    172        case AttributeDefinitionBands.CONTEXT_CLASS:
    173            return !contextClass;
    174        case AttributeDefinitionBands.CONTEXT_METHOD:
    175            return !contextMethod;
    176        case AttributeDefinitionBands.CONTEXT_FIELD:
    177            return !contextField;
    178        case AttributeDefinitionBands.CONTEXT_CODE:
    179            return !contextCode;
    180        }
    181        return false;
    182    }
    183
    184    @Override
    185    protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff,
    186        final Label[] labels) {
    187        final byte[] attributeContents = new byte[len];
    188        System.arraycopy(cr.b, off, attributeContents, 0, len);
    189        return new NewAttribute(cr, type, layout, attributeContents, buf, codeOff, labels);
    190    }
    191
    192    public String readClass(final int index) {
    193        return classReader.readClass(index, buf);
    194    }
    195
    196    public Object readConst(final int index) {
    197        return classReader.readConst(index, buf);
    198    }
    199
    200    public String readUTF8(final int index) {
    201        return classReader.readUTF8(index, buf);
    202    }
    203}