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