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}