    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one
    003 * or more contributor license agreements.  See the NOTICE file
    004 * distributed with this work for additional information
    005 * regarding copyright ownership.  The ASF licenses this file
    006 * to you under the Apache License, Version 2.0 (the
    007 * "License"); you may not use this file except in compliance
    008 * with the License.  You may obtain a copy of the License at
    009 *
    010 *   https://www.apache.org/licenses/LICENSE-2.0
    011 *
    012 * Unless required by applicable law or agreed to in writing,
    013 * software distributed under the License is distributed on an
    014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015 * KIND, either express or implied.  See the License for the
    016 * specific language governing permissions and limitations
    017 * under the License.
    018 */
    019package org.apache.commons.compress.harmony.pack200;
    020
    021import org.objectweb.asm.Attribute;
    022import org.objectweb.asm.ClassReader;
    023import org.objectweb.asm.Label;
    024
    025/**
    026 * NewAttribute extends {@code Attribute} and manages unknown attributes encountered by ASM that have had a layout definition given to pack200 (for example via
    027 * one of the -C, -M, -F or -D command line options)
    028 */
    029public class NewAttribute extends Attribute {
    030    /**
    031     * ErrorAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had an error action specified to pack200 (for example via
    032     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=error)
    033     */
    034    public static class ErrorAttribute extends NewAttribute {
    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     * PassAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a pass action specified to pack200 (for example via
    047     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=pass)
    048     */
    049    public static class PassAttribute extends NewAttribute {
    050        public PassAttribute(final String type, final int context) {
    051            super(type, "", context);
    052        }
    053
    054        @Override
    055        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
    056            throw new Segment.PassException();
    057        }
    058    }
    059
    060    /**
    061     * StripAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a strip action specified to pack200 (for example via
    062     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=strip)
    063     */
    064    public static class StripAttribute extends NewAttribute {
    065        public StripAttribute(final String type, final int context) {
    066            super(type, "", context);
    067        }
    068
    069        @Override
    070        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
    071            // TODO Not sure if this works, can we really strip an attribute if we don't know the layout?
    072            return null;
    073        }
    074    }
    075
    076    private boolean contextClass;
    077    private boolean contextMethod;
    078    private boolean contextField;
    079    private boolean contextCode;
    080    private final String layout;
    081    private byte[] contents;
    082    private int codeOff;
    083    private Label[] labels;
    084    private ClassReader classReader;
    085    private char[] buf;
    086
    087    public NewAttribute(final ClassReader classReader, final String type, final String layout, final byte[] contents, final char[] buf, final int codeOff,
    088            final Label[] labels) {
    089        super(type);
    090        this.classReader = classReader;
    091        this.contents = contents;
    092        this.layout = layout;
    093        this.codeOff = codeOff;
    094        this.labels = labels;
    095        this.buf = buf;
    096    }
    097
    098    public NewAttribute(final String type, final String layout, final int context) {
    099        super(type);
    100        this.layout = layout;
    101        addContext(context);
    102    }
    103
    104    public void addContext(final int context) {
    105        switch (context) {
    106        case AttributeDefinitionBands.CONTEXT_CLASS:
    107            contextClass = true;
    108            break;
    109        case AttributeDefinitionBands.CONTEXT_METHOD:
    110            contextMethod = true;
    111            break;
    112        case AttributeDefinitionBands.CONTEXT_FIELD:
    113            contextField = true;
    114            break;
    115        case AttributeDefinitionBands.CONTEXT_CODE:
    116            contextCode = true;
    117            break;
    118        }
    119    }
    120
    121    public byte[] getBytes() {
    122        return contents;
    123    }
    124
    125    public Label getLabel(final int index) {
    126        return labels[index];
    127    }
    128
    129    public String getLayout() {
    130        return layout;
    131    }
    132
    133    @Override
    134    public boolean isCodeAttribute() {
    135        return codeOff != -1;
    136    }
    137
    138    public boolean isContextClass() {
    139        return contextClass;
    140    }
    141
    142    public boolean isContextCode() {
    143        return contextCode;
    144    }
    145
    146    public boolean isContextField() {
    147        return contextField;
    148    }
    149
    150    public boolean isContextMethod() {
    151        return contextMethod;
    152    }
    153
    154    @Override
    155    public boolean isUnknown() {
    156        return false;
    157    }
    158
    159    public boolean isUnknown(final int context) {
    160        switch (context) {
    161        case AttributeDefinitionBands.CONTEXT_CLASS:
    162            return !contextClass;
    163        case AttributeDefinitionBands.CONTEXT_METHOD:
    164            return !contextMethod;
    165        case AttributeDefinitionBands.CONTEXT_FIELD:
    166            return !contextField;
    167        case AttributeDefinitionBands.CONTEXT_CODE:
    168            return !contextCode;
    169        }
    170        return false;
    171    }
    172
    173    @Override
    174    protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
    175        final byte[] attributeContents = new byte[len];
    176        System.arraycopy(cr.b, off, attributeContents, 0, len);
    177        return new NewAttribute(cr, type, layout, attributeContents, buf, codeOff, labels);
    178    }
    179
    180    public String readClass(final int index) {
    181        return classReader.readClass(index, buf);
    182    }
    183
    184    public Object readConst(final int index) {
    185        return classReader.readConst(index, buf);
    186    }
    187
    188    public String readUTF8(final int index) {
    189        return classReader.readUTF8(index, buf);
    190    }
    191}