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}